diff options
Diffstat (limited to 'drivers/target')
42 files changed, 2660 insertions, 3701 deletions
| diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 035c2c762537..339f97f7085b 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -735,7 +735,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)  	list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {  		spin_lock(&cmd->istate_lock);  		if ((cmd->i_state == ISTATE_SENT_STATUS) && -		    (cmd->stat_sn < exp_statsn)) { +		    iscsi_sna_lt(cmd->stat_sn, exp_statsn)) {  			cmd->i_state = ISTATE_REMOVE;  			spin_unlock(&cmd->istate_lock);  			iscsit_add_cmd_to_immediate_queue(cmd, conn, @@ -767,9 +767,8 @@ static int iscsit_handle_scsi_cmd(  	struct iscsi_conn *conn,  	unsigned char *buf)  { -	int	data_direction, cmdsn_ret = 0, immed_ret, ret, transport_ret; -	int	dump_immediate_data = 0, send_check_condition = 0, payload_length; -	struct iscsi_cmd	*cmd = NULL; +	int data_direction, payload_length, cmdsn_ret = 0, immed_ret; +	struct iscsi_cmd *cmd = NULL;  	struct iscsi_scsi_req *hdr;  	int iscsi_task_attr;  	int sam_task_attr; @@ -956,38 +955,26 @@ done:  		" ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,  		hdr->cmdsn, hdr->data_length, payload_length, conn->cid); -	/* -	 * The CDB is going to an se_device_t. -	 */ -	ret = transport_lookup_cmd_lun(&cmd->se_cmd, -				       scsilun_to_int(&hdr->lun)); -	if (ret < 0) { -		if (cmd->se_cmd.scsi_sense_reason == TCM_NON_EXISTENT_LUN) { -			pr_debug("Responding to non-acl'ed," -				" non-existent or non-exported iSCSI LUN:" -				" 0x%016Lx\n", get_unaligned_le64(&hdr->lun)); +	cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, +						     scsilun_to_int(&hdr->lun)); +	if (cmd->sense_reason) +		goto attach_cmd; + +	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);  		} -		send_check_condition = 1; +  		goto attach_cmd;  	} -	transport_ret = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); -	if (transport_ret == -ENOMEM) { +	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); -	} else if (transport_ret < 0) { -		/* -		 * Unsupported SAM Opcode.  CHECK_CONDITION will be sent -		 * in iscsit_execute_cmd() during the CmdSN OOO Execution -		 * Mechinism. -		 */ -		send_check_condition = 1; -	} else { -		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); +			ISCSI_REASON_BOOKMARK_NO_RESOURCES, +			1, 1, buf, cmd);  	}  attach_cmd: @@ -1000,11 +987,12 @@ attach_cmd:  	 */  	core_alua_check_nonop_delay(&cmd->se_cmd); -	ret = iscsit_allocate_iovecs(cmd); -	if (ret < 0) +	if (iscsit_allocate_iovecs(cmd) < 0) {  		return iscsit_add_reject_from_cmd(  				ISCSI_REASON_BOOKMARK_NO_RESOURCES,  				1, 0, buf, cmd); +	} +  	/*  	 * Check the CmdSN against ExpCmdSN/MaxCmdSN here if  	 * the Immediate Bit is not set, and no Immediate @@ -1031,10 +1019,7 @@ attach_cmd:  	 * If no Immediate Data is attached, it's OK to return now.  	 */  	if (!cmd->immediate_data) { -		if (send_check_condition) -			return 0; - -		if (cmd->unsolicited_data) { +		if (!cmd->sense_reason && cmd->unsolicited_data) {  			iscsit_set_dataout_sequence_values(cmd);  			spin_lock_bh(&cmd->dataout_timeout_lock); @@ -1050,19 +1035,17 @@ attach_cmd:  	 * thread.  They are processed in CmdSN order by  	 * iscsit_check_received_cmdsn() below.  	 */ -	if (send_check_condition) { +	if (cmd->sense_reason) {  		immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; -		dump_immediate_data = 1;  		goto after_immediate_data;  	}  	/*  	 * Call directly into transport_generic_new_cmd() to perform  	 * the backend memory allocation.  	 */ -	ret = transport_generic_new_cmd(&cmd->se_cmd); -	if (ret < 0) { +	cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); +	if (cmd->sense_reason) {  		immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; -		dump_immediate_data = 1;  		goto after_immediate_data;  	} @@ -1079,7 +1062,7 @@ after_immediate_data:  		 * Special case for Unsupported SAM WRITE Opcodes  		 * and ImmediateData=Yes.  		 */ -		if (dump_immediate_data) { +		if (cmd->sense_reason) {  			if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)  				return -1;  		} else if (cmd->unsolicited_data) { @@ -1272,8 +1255,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)  		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) || -		     (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION)) +		if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE))  			dump_unsolicited_data = 1;  		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); @@ -1742,7 +1724,6 @@ static int iscsit_handle_task_mgt_cmd(  		ret = transport_lookup_tmr_lun(&cmd->se_cmd,  					       scsilun_to_int(&hdr->lun));  		if (ret < 0) { -			cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  			se_tmr->response = ISCSI_TMF_RSP_NO_LUN;  			goto attach;  		} @@ -1751,10 +1732,8 @@ static int iscsit_handle_task_mgt_cmd(  	switch (function) {  	case ISCSI_TM_FUNC_ABORT_TASK:  		se_tmr->response = iscsit_tmr_abort_task(cmd, buf); -		if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) { -			cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; +		if (se_tmr->response)  			goto attach; -		}  		break;  	case ISCSI_TM_FUNC_ABORT_TASK_SET:  	case ISCSI_TM_FUNC_CLEAR_ACA: @@ -1763,14 +1742,12 @@ static int iscsit_handle_task_mgt_cmd(  		break;  	case ISCSI_TM_FUNC_TARGET_WARM_RESET:  		if (iscsit_tmr_task_warm_reset(conn, tmr_req, buf) < 0) { -			cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  			se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED;  			goto attach;  		}  		break;  	case ISCSI_TM_FUNC_TARGET_COLD_RESET:  		if (iscsit_tmr_task_cold_reset(conn, tmr_req, buf) < 0) { -			cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  			se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED;  			goto attach;  		} @@ -1781,7 +1758,7 @@ static int iscsit_handle_task_mgt_cmd(  		 * Perform sanity checks on the ExpDataSN only if the  		 * TASK_REASSIGN was successful.  		 */ -		if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) +		if (se_tmr->response)  			break;  		if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0) @@ -1792,7 +1769,6 @@ static int iscsit_handle_task_mgt_cmd(  	default:  		pr_err("Unknown TMR function: 0x%02x, protocol"  			" error.\n", function); -		cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  		se_tmr->response = ISCSI_TMF_RSP_NOT_SUPPORTED;  		goto attach;  	} @@ -2360,7 +2336,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)  	if (!conn_p)  		return; -	cmd = iscsit_allocate_cmd(conn_p, GFP_KERNEL); +	cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC);  	if (!cmd) {  		iscsit_dec_conn_usage_count(conn_p);  		return; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index ff6fd4fb624d..78d75c8567d0 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -235,7 +235,7 @@ static struct se_tpg_np *lio_target_call_addnptotpg(  	 * iSER/SCTP (TODO, software emulation with osc-iwarp)  	 * iSER/IB (TODO, hardware available)  	 * -	 * can be enabled with atributes under +	 * can be enabled with attributes under  	 * sys/kernel/config/iscsi/$IQN/$TPG/np/$IP:$PORT/  	 *  	 */ @@ -754,9 +754,33 @@ static ssize_t lio_target_nacl_store_cmdsn_depth(  TF_NACL_BASE_ATTR(lio_target, cmdsn_depth, S_IRUGO | S_IWUSR); +static ssize_t lio_target_nacl_show_tag( +	struct se_node_acl *se_nacl, +	char *page) +{ +	return snprintf(page, PAGE_SIZE, "%s", se_nacl->acl_tag); +} + +static ssize_t lio_target_nacl_store_tag( +	struct se_node_acl *se_nacl, +	const char *page, +	size_t count) +{ +	int ret; + +	ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page); + +	if (ret < 0) +		return ret; +	return count; +} + +TF_NACL_BASE_ATTR(lio_target, tag, S_IRUGO | S_IWUSR); +  static struct configfs_attribute *lio_target_initiator_attrs[] = {  	&lio_target_nacl_info.attr,  	&lio_target_nacl_cmdsn_depth.attr, +	&lio_target_nacl_tag.attr,  	NULL,  }; @@ -803,7 +827,7 @@ static struct se_node_acl *lio_target_make_nodeacl(  	acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl);  	stats_cg = &se_nacl->acl_fabric_stat_group; -	stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  				GFP_KERNEL);  	if (!stats_cg->default_groups) {  		pr_err("Unable to allocate memory for" @@ -1268,7 +1292,7 @@ static struct se_wwn *lio_target_call_coreaddtiqn(  	 */  	stats_cg = &tiqn->tiqn_wwn.fabric_stat_group; -	stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, +	stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,  				GFP_KERNEL);  	if (!stats_cg->default_groups) {  		pr_err("Unable to allocate memory for" diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 21048dbf7d13..7a333d28d9a2 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -474,7 +474,7 @@ struct iscsi_cmd {  	struct scatterlist	*first_data_sg;  	u32			first_data_sg_off;  	u32			kmapped_nents; - +	sense_reason_t		sense_reason;  }  ____cacheline_aligned;  struct iscsi_tmr_req { diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 8aacf611b86d..8e6298cc8839 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -410,11 +410,11 @@ static int iscsit_dataout_pre_datapduinorder_yes(  	/*  	 * For DataSequenceInOrder=Yes: If the offset is greater than the global  	 * DataPDUInOrder=Yes offset counter in struct iscsi_cmd a protcol error has -	 * occured and fail the connection. +	 * occurred and fail the connection.  	 *  	 * For DataSequenceInOrder=No: If the offset is greater than the per  	 * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol -	 * error has occured and fail the connection. +	 * error has occurred and fail the connection.  	 */  	if (conn->sess->sess_ops->DataSequenceInOrder) {  		if (be32_to_cpu(hdr->offset) != cmd->write_data_done) { @@ -801,7 +801,7 @@ void iscsit_start_time2retain_handler(struct iscsi_session *sess)  {  	int tpg_active;  	/* -	 * Only start Time2Retain timer when the assoicated TPG is still in +	 * Only start Time2Retain timer when the associated TPG is still in  	 * an ACTIVE (eg: not disabled or shutdown) state.  	 */  	spin_lock(&ISCSI_TPG_S(sess)->tpg_state_lock); diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 21f29d91a8cb..0b52a2371305 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -929,11 +929,10 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)  	case ISCSI_OP_SCSI_CMD:  		/*  		 * Go ahead and send the CHECK_CONDITION status for -		 * any SCSI CDB exceptions that may have occurred, also -		 * handle the SCF_SCSI_RESERVATION_CONFLICT case here as well. +		 * any SCSI CDB exceptions that may have occurred.  		 */ -		if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { -			if (se_cmd->scsi_sense_reason == TCM_RESERVATION_CONFLICT) { +		if (cmd->sense_reason) { +			if (cmd->sense_reason == TCM_RESERVATION_CONFLICT) {  				cmd->i_state = ISTATE_SEND_STATUS;  				spin_unlock_bh(&cmd->istate_lock);  				iscsit_add_cmd_to_response_queue(cmd, cmd->conn, @@ -956,7 +955,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)  			 * exception  			 */  			return transport_send_check_condition_and_sense(se_cmd, -					se_cmd->scsi_sense_reason, 0); +					cmd->sense_reason, 0);  		}  		/*  		 * Special case for delayed CmdSN with Immediate @@ -1013,7 +1012,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)  		iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);  		break;  	case ISCSI_OP_SCSI_TMFUNC: -		if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { +		if (cmd->se_cmd.se_tmr_req->response) {  			spin_unlock_bh(&cmd->istate_lock);  			iscsit_add_cmd_to_response_queue(cmd, cmd->conn,  					cmd->i_state); diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 17d8c20094fd..9ac4c151eae4 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -372,7 +372,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)  		 * made generic here.  		 */  		if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && -		     (cmd->cmd_sn >= conn->sess->exp_cmd_sn)) { +		     iscsi_sna_gte(cmd->stat_sn, conn->sess->exp_cmd_sn)) {  			list_del(&cmd->i_conn_node);  			spin_unlock_bh(&conn->cmd_lock);  			iscsit_free_cmd(cmd); diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index f8dbec05d5e5..fdb632f0ab85 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -127,13 +127,13 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)  	initiatorname_param = iscsi_find_param_from_key(  			INITIATORNAME, conn->param_list); -	if (!initiatorname_param) -		return -1; -  	sessiontype_param = iscsi_find_param_from_key(  			SESSIONTYPE, conn->param_list); -	if (!sessiontype_param) +	if (!initiatorname_param || !sessiontype_param) { +		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, +			ISCSI_LOGIN_STATUS_MISSING_FIELDS);  		return -1; +	}  	sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0; @@ -254,9 +254,9 @@ static int iscsi_login_zero_tsih_s1(  		kfree(sess);  		return -ENOMEM;  	} -	spin_lock(&sess_idr_lock); +	spin_lock_bh(&sess_idr_lock);  	ret = idr_get_new(&sess_idr, NULL, &sess->session_index); -	spin_unlock(&sess_idr_lock); +	spin_unlock_bh(&sess_idr_lock);  	if (ret < 0) {  		pr_err("idr_get_new() for sess_idr failed\n"); @@ -1118,10 +1118,8 @@ new_sess_out:  		idr_remove(&sess_idr, conn->sess->session_index);  		spin_unlock_bh(&sess_idr_lock);  	} -	if (conn->sess->sess_ops) -		kfree(conn->sess->sess_ops); -	if (conn->sess) -		kfree(conn->sess); +	kfree(conn->sess->sess_ops); +	kfree(conn->sess);  old_sess_out:  	iscsi_stop_login_thread_timer(np);  	/* diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index e9053a04f24c..9d902aefe01a 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -620,8 +620,11 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log  			login->req_buf,  			payload_length,  			conn); -	if (ret < 0) +	if (ret < 0) { +		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, +				ISCSI_LOGIN_STATUS_INIT_ERR);  		return -1; +	}  	if (login->first_request)  		if (iscsi_target_check_first_request(conn, login) < 0) @@ -636,8 +639,11 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log  			login->rsp_buf,  			&login->rsp_length,  			conn->param_list); -	if (ret < 0) +	if (ret < 0) { +		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, +				ISCSI_LOGIN_STATUS_INIT_ERR);  		return -1; +	}  	if (!login->auth_complete &&  	     ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication) { diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 90b740048f26..d89164287d00 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -154,22 +154,18 @@ static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *para  	}  	INIT_LIST_HEAD(¶m->p_list); -	param->name = kzalloc(strlen(name) + 1, GFP_KERNEL); +	param->name = kstrdup(name, GFP_KERNEL);  	if (!param->name) {  		pr_err("Unable to allocate memory for parameter name.\n");  		goto out;  	} -	param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); +	param->value = kstrdup(value, GFP_KERNEL);  	if (!param->value) {  		pr_err("Unable to allocate memory for parameter value.\n");  		goto out;  	} -	memcpy(param->name, name, strlen(name)); -	param->name[strlen(name)] = '\0'; -	memcpy(param->value, value, strlen(value)); -	param->value[strlen(value)] = '\0';  	param->phase		= phase;  	param->scope		= scope;  	param->sender		= sender; @@ -635,11 +631,8 @@ void iscsi_release_param_list(struct iscsi_param_list *param_list)  		list_del(¶m->p_list);  		kfree(param->name); -		param->name = NULL;  		kfree(param->value); -		param->value = NULL;  		kfree(param); -		param = NULL;  	}  	iscsi_release_extra_responses(param_list); @@ -687,15 +680,12 @@ int iscsi_update_param_value(struct iscsi_param *param, char *value)  {  	kfree(param->value); -	param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); +	param->value = kstrdup(value, GFP_KERNEL);  	if (!param->value) {  		pr_err("Unable to allocate memory for value.\n");  		return -ENOMEM;  	} -	memcpy(param->value, value, strlen(value)); -	param->value[strlen(value)] = '\0'; -  	pr_debug("iSCSI Parameter updated to %s=%s\n",  			param->name, param->value);  	return 0; @@ -1432,6 +1422,7 @@ static struct iscsi_param *iscsi_check_key(  			break;  		case PHASE_OPERATIONAL:  			pr_debug("Operational phase.\n"); +			break;  		default:  			pr_debug("Unknown phase.\n");  		} diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index 4a99820d063b..9d4417aae921 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -50,8 +50,8 @@ u8 iscsit_tmr_abort_task(  	if (!ref_cmd) {  		pr_err("Unable to locate RefTaskTag: 0x%08x on CID:"  			" %hu.\n", hdr->rtt, conn->cid); -		return (be32_to_cpu(hdr->refcmdsn) >= conn->sess->exp_cmd_sn && -			be32_to_cpu(hdr->refcmdsn) <= conn->sess->max_cmd_sn) ? +		return (iscsi_sna_gte(be32_to_cpu(hdr->refcmdsn), conn->sess->exp_cmd_sn) && +			iscsi_sna_lte(be32_to_cpu(hdr->refcmdsn), conn->sess->max_cmd_sn)) ?  			ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK;  	}  	if (ref_cmd->cmd_sn != be32_to_cpu(hdr->refcmdsn)) { diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c index 9d881a000e42..81289520f96b 100644 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ b/drivers/target/iscsi/iscsi_target_tq.c @@ -66,8 +66,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)  		return NULL;  	} -	list_for_each_entry(ts, &inactive_ts_list, ts_list) -		break; +	ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list);  	list_del(&ts->ts_list);  	iscsit_global->inactive_ts--; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 1a91195ab619..7ce350578c82 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -500,8 +500,8 @@ struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *c  		spin_unlock_bh(&conn->immed_queue_lock);  		return NULL;  	} -	list_for_each_entry(qr, &conn->immed_queue_list, qr_list) -		break; +	qr = list_first_entry(&conn->immed_queue_list, +			      struct iscsi_queue_req, qr_list);  	list_del(&qr->qr_list);  	if (qr->cmd) @@ -575,8 +575,8 @@ struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *co  		return NULL;  	} -	list_for_each_entry(qr, &conn->response_queue_list, qr_list) -		break; +	qr = list_first_entry(&conn->response_queue_list, +			      struct iscsi_queue_req, qr_list);  	list_del(&qr->qr_list);  	if (qr->cmd) @@ -684,7 +684,7 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)  void iscsit_free_cmd(struct iscsi_cmd *cmd)  {  	/* -	 * Determine if a struct se_cmd is assoicated with +	 * Determine if a struct se_cmd is associated with  	 * this struct iscsi_cmd.  	 */  	switch (cmd->iscsi_opcode) { diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 7b54893db665..dd7a84ee78e1 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -53,7 +53,6 @@ struct tcm_loop_hba {  	struct se_hba_s *se_hba;  	struct se_lun *tl_hba_lun;  	struct se_port *tl_hba_lun_sep; -	struct se_device_s *se_dev_hba_ptr;  	struct tcm_loop_nexus *tl_nexus;  	struct device dev;  	struct Scsi_Host *sh; diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig index 132da544eafc..1614bc710d4e 100644 --- a/drivers/target/sbp/Kconfig +++ b/drivers/target/sbp/Kconfig @@ -1,6 +1,6 @@  config SBP_TARGET  	tristate "FireWire SBP-2 fabric module" -	depends on FIREWIRE && EXPERIMENTAL +	depends on FIREWIRE  	help  	  Say Y or M here to enable SCSI target functionality over FireWire.  	  This enables you to expose SCSI devices to other nodes on the FireWire diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 0d6d7c1f025e..2e8d06f198ae 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -704,16 +704,17 @@ static void session_maintenance_work(struct work_struct *work)  static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,  		struct sbp_target_agent *agent)  { -	__be32 state; +	int state;  	switch (tcode) {  	case TCODE_READ_QUADLET_REQUEST:  		pr_debug("tgt_agent AGENT_STATE READ\n");  		spin_lock_bh(&agent->lock); -		state = cpu_to_be32(agent->state); +		state = agent->state;  		spin_unlock_bh(&agent->lock); -		memcpy(data, &state, sizeof(state)); + +		*(__be32 *)data = cpu_to_be32(state);  		return RCODE_COMPLETE; @@ -2207,20 +2208,23 @@ static struct se_portal_group *sbp_make_tpg(  	tport->mgt_agt = sbp_management_agent_register(tport);  	if (IS_ERR(tport->mgt_agt)) {  		ret = PTR_ERR(tport->mgt_agt); -		kfree(tpg); -		return ERR_PTR(ret); +		goto out_free_tpg;  	}  	ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,  			&tpg->se_tpg, (void *)tpg,  			TRANSPORT_TPG_TYPE_NORMAL); -	if (ret < 0) { -		sbp_management_agent_unregister(tport->mgt_agt); -		kfree(tpg); -		return ERR_PTR(ret); -	} +	if (ret < 0) +		goto out_unreg_mgt_agt;  	return &tpg->se_tpg; + +out_unreg_mgt_agt: +	sbp_management_agent_unregister(tport->mgt_agt); +out_free_tpg: +	tport->tpg = NULL; +	kfree(tpg); +	return ERR_PTR(ret);  }  static void sbp_drop_tpg(struct se_portal_group *se_tpg) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 9a5f9a7aecd2..85140f7dde1e 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -3,8 +3,7 @@   *   * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA)   * - * Copyright (c) 2009-2010 Rising Tide Systems - * Copyright (c) 2009-2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -41,7 +40,7 @@  #include "target_core_alua.h"  #include "target_core_ua.h" -static int core_alua_check_transition(int state, int *primary); +static sense_reason_t core_alua_check_transition(int state, int *primary);  static int core_alua_set_tg_pt_secondary_state(  		struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,  		struct se_port *port, int explict, int offline); @@ -59,15 +58,17 @@ struct t10_alua_lu_gp *default_lu_gp;   *   * See spc4r17 section 6.27   */ -int target_emulate_report_target_port_groups(struct se_cmd *cmd) +sense_reason_t +target_emulate_report_target_port_groups(struct se_cmd *cmd)  { -	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; +	struct se_device *dev = cmd->se_dev;  	struct se_port *port;  	struct t10_alua_tg_pt_gp *tg_pt_gp;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;  	unsigned char *buf;  	u32 rd_len = 0, off;  	int ext_hdr = (cmd->t_task_cdb[1] & 0x20); +  	/*  	 * Skip over RESERVED area to first Target port group descriptor  	 * depending on the PARAMETER DATA FORMAT type.. @@ -81,13 +82,14 @@ int target_emulate_report_target_port_groups(struct se_cmd *cmd)  		pr_warn("REPORT TARGET PORT GROUPS allocation length %u too"  			" small for %s header\n", cmd->data_length,  			(ext_hdr) ? "extended" : "normal"); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); -	list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list, +	spin_lock(&dev->t10_alua.tg_pt_gps_lock); +	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,  			tg_pt_gp_list) {  		/*  		 * Check if the Target port group and Target port descriptor list @@ -160,7 +162,7 @@ int target_emulate_report_target_port_groups(struct se_cmd *cmd)  		}  		spin_unlock(&tg_pt_gp->tg_pt_gp_lock);  	} -	spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  	/*  	 * Set the RETURN DATA LENGTH set in the header of the DataIN Payload  	 */ @@ -200,32 +202,33 @@ int target_emulate_report_target_port_groups(struct se_cmd *cmd)   *   * See spc4r17 section 6.35   */ -int target_emulate_set_target_port_groups(struct se_cmd *cmd) +sense_reason_t +target_emulate_set_target_port_groups(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	struct se_port *port, *l_port = cmd->se_lun->lun_sep;  	struct se_node_acl *nacl = cmd->se_sess->se_node_acl;  	struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem;  	unsigned char *buf;  	unsigned char *ptr; +	sense_reason_t rc;  	u32 len = 4; /* Skip over RESERVED area in header */ -	int alua_access_state, primary = 0, rc; +	int alua_access_state, primary = 0;  	u16 tg_pt_id, rtpi; -	if (!l_port) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; -	} +	if (!l_port) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +  	if (cmd->data_length < 4) {  		pr_warn("SET TARGET PORT GROUPS parameter list length %u too"  			" small\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		return TCM_INVALID_PARAMETER_LIST;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	/*  	 * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed @@ -234,8 +237,7 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  	l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem;  	if (!l_tg_pt_gp_mem) {  		pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -		rc = -EINVAL; +		rc = TCM_UNSUPPORTED_SCSI_OPCODE;  		goto out;  	}  	spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); @@ -243,24 +245,22 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  	if (!l_tg_pt_gp) {  		spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);  		pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -		rc = -EINVAL; +		rc = TCM_UNSUPPORTED_SCSI_OPCODE;  		goto out;  	} -	rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA);  	spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); -	if (!rc) { +	if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA)) {  		pr_debug("Unable to process SET_TARGET_PORT_GROUPS"  				" while TPGS_EXPLICT_ALUA is disabled\n"); -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -		rc = -EINVAL; +		rc = TCM_UNSUPPORTED_SCSI_OPCODE;  		goto out;  	}  	ptr = &buf[4]; /* Skip over RESERVED area in header */  	while (len < cmd->data_length) { +		bool found = false;  		alua_access_state = (ptr[0] & 0x0f);  		/*  		 * Check the received ALUA access state, and determine if @@ -268,7 +268,7 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  		 * access state.  		 */  		rc = core_alua_check_transition(alua_access_state, &primary); -		if (rc != 0) { +		if (rc) {  			/*  			 * If the SET TARGET PORT GROUPS attempts to establish  			 * an invalid combination of target port asymmetric @@ -279,11 +279,9 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  			 * REQUEST, and the additional sense code set to INVALID  			 * FIELD IN PARAMETER LIST.  			 */ -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			rc = -EINVAL;  			goto out;  		} -		rc = -1; +  		/*  		 * If the ASYMMETRIC ACCESS STATE field (see table 267)  		 * specifies a primary target port asymmetric access state, @@ -303,9 +301,9 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  			 * Locate the matching target port group ID from  			 * the global tg_pt_gp list  			 */ -			spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +			spin_lock(&dev->t10_alua.tg_pt_gps_lock);  			list_for_each_entry(tg_pt_gp, -					&su_dev->t10_alua.tg_pt_gps_list, +					&dev->t10_alua.tg_pt_gps_list,  					tg_pt_gp_list) {  				if (!tg_pt_gp->tg_pt_gp_valid_id)  					continue; @@ -315,27 +313,20 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  				atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);  				smp_mb__after_atomic_inc(); -				spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); -				rc = core_alua_do_port_transition(tg_pt_gp, +				spin_unlock(&dev->t10_alua.tg_pt_gps_lock); + +				if (!core_alua_do_port_transition(tg_pt_gp,  						dev, l_port, nacl, -						alua_access_state, 1); +						alua_access_state, 1)) +					found = true; -				spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +				spin_lock(&dev->t10_alua.tg_pt_gps_lock);  				atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);  				smp_mb__after_atomic_dec();  				break;  			} -			spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); -			/* -			 * If not matching target port group ID can be located -			 * throw an exception with ASCQ: INVALID_PARAMETER_LIST -			 */ -			if (rc != 0) { -				cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -				rc = -EINVAL; -				goto out; -			} +			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  		} else {  			/*  			 * Extact the RELATIVE TARGET PORT IDENTIFIER to identify @@ -354,25 +345,22 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)  					continue;  				tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; +  				spin_unlock(&dev->se_port_lock); -				rc = core_alua_set_tg_pt_secondary_state( -						tg_pt_gp_mem, port, 1, 1); +				if (!core_alua_set_tg_pt_secondary_state( +						tg_pt_gp_mem, port, 1, 1)) +					found = true;  				spin_lock(&dev->se_port_lock);  				break;  			}  			spin_unlock(&dev->se_port_lock); -			/* -			 * If not matching relative target port identifier can -			 * be located, throw an exception with ASCQ: -			 * INVALID_PARAMETER_LIST -			 */ -			if (rc != 0) { -				cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -				rc = -EINVAL; -				goto out; -			} +		} + +		if (!found) { +			rc = TCM_INVALID_PARAMETER_LIST; +			goto out;  		}  		ptr += 4; @@ -523,40 +511,27 @@ static inline int core_alua_state_transition(  }  /* - * Used for alua_type SPC_ALUA_PASSTHROUGH and SPC2_ALUA_DISABLED - * in transport_cmd_sequencer().  This function is assigned to - * struct t10_alua *->state_check() in core_setup_alua() - */ -static int core_alua_state_check_nop( -	struct se_cmd *cmd, -	unsigned char *cdb, -	u8 *alua_ascq) -{ -	return 0; -} - -/* - * Used for alua_type SPC3_ALUA_EMULATED in transport_cmd_sequencer(). - * This function is assigned to struct t10_alua *->state_check() in - * core_setup_alua() - * - * Also, this function can return three different return codes to - * signal transport_generic_cmd_sequencer() - *   * return 1: Is used to signal LUN not accecsable, and check condition/not ready   * return 0: Used to signal success   * reutrn -1: Used to signal failure, and invalid cdb field   */ -static int core_alua_state_check( -	struct se_cmd *cmd, -	unsigned char *cdb, -	u8 *alua_ascq) +sense_reason_t +target_alua_state_check(struct se_cmd *cmd)  { +	struct se_device *dev = cmd->se_dev; +	unsigned char *cdb = cmd->t_task_cdb;  	struct se_lun *lun = cmd->se_lun;  	struct se_port *port = lun->lun_sep;  	struct t10_alua_tg_pt_gp *tg_pt_gp;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;  	int out_alua_state, nonop_delay_msecs; +	u8 alua_ascq; +	int ret; + +	if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) +		return 0; +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) +		return 0;  	if (!port)  		return 0; @@ -565,11 +540,11 @@ static int core_alua_state_check(  	 * access state: OFFLINE  	 */  	if (atomic_read(&port->sep_tg_pt_secondary_offline)) { -		*alua_ascq = ASCQ_04H_ALUA_OFFLINE;  		pr_debug("ALUA: Got secondary offline status for local"  				" target port\n"); -		*alua_ascq = ASCQ_04H_ALUA_OFFLINE; -		return 1; +		alua_ascq = ASCQ_04H_ALUA_OFFLINE; +		ret = 1; +		goto out;  	}  	 /*  	 * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the @@ -594,14 +569,18 @@ static int core_alua_state_check(  	switch (out_alua_state) {  	case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: -		return core_alua_state_nonoptimized(cmd, cdb, -					nonop_delay_msecs, alua_ascq); +		ret = core_alua_state_nonoptimized(cmd, cdb, +					nonop_delay_msecs, &alua_ascq); +		break;  	case ALUA_ACCESS_STATE_STANDBY: -		return core_alua_state_standby(cmd, cdb, alua_ascq); +		ret = core_alua_state_standby(cmd, cdb, &alua_ascq); +		break;  	case ALUA_ACCESS_STATE_UNAVAILABLE: -		return core_alua_state_unavailable(cmd, cdb, alua_ascq); +		ret = core_alua_state_unavailable(cmd, cdb, &alua_ascq); +		break;  	case ALUA_ACCESS_STATE_TRANSITION: -		return core_alua_state_transition(cmd, cdb, alua_ascq); +		ret = core_alua_state_transition(cmd, cdb, &alua_ascq); +		break;  	/*  	 * OFFLINE is a secondary ALUA target port group access state, that is  	 * handled above with struct se_port->sep_tg_pt_secondary_offline=1 @@ -610,7 +589,24 @@ static int core_alua_state_check(  	default:  		pr_err("Unknown ALUA access state: 0x%02x\n",  				out_alua_state); -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD; +	} + +out: +	if (ret > 0) { +		/* +		 * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; +		 * The ALUA additional sense code qualifier (ASCQ) is determined +		 * by the ALUA primary or secondary access state.. +		 */ +		pr_debug("[%s]: ALUA TG Port not available, " +			"SenseKey: NOT_READY, ASC/ASCQ: " +			"0x04/0x%02x\n", +			cmd->se_tfo->get_fabric_name(), alua_ascq); + +		cmd->scsi_asc = 0x04; +		cmd->scsi_ascq = alua_ascq; +		return TCM_CHECK_CONDITION_NOT_READY;  	}  	return 0; @@ -619,7 +615,8 @@ static int core_alua_state_check(  /*   * Check implict and explict ALUA state change request.   */ -static int core_alua_check_transition(int state, int *primary) +static sense_reason_t +core_alua_check_transition(int state, int *primary)  {  	switch (state) {  	case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED: @@ -641,7 +638,7 @@ static int core_alua_check_transition(int state, int *primary)  		break;  	default:  		pr_err("Unknown ALUA access state: 0x%02x\n", state); -		return -EINVAL; +		return TCM_INVALID_PARAMETER_LIST;  	}  	return 0; @@ -758,8 +755,7 @@ static int core_alua_update_tpg_primary_metadata(  	int primary_state,  	unsigned char *md_buf)  { -	struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; -	struct t10_wwn *wwn = &su_dev->t10_wwn; +	struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn;  	char path[ALUA_METADATA_PATH_LEN];  	int len; @@ -899,7 +895,6 @@ int core_alua_do_port_transition(  {  	struct se_device *dev;  	struct se_port *port; -	struct se_subsystem_dev *su_dev;  	struct se_node_acl *nacl;  	struct t10_alua_lu_gp *lu_gp;  	struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; @@ -949,14 +944,13 @@ int core_alua_do_port_transition(  				lu_gp_mem_list) {  		dev = lu_gp_mem->lu_gp_mem_dev; -		su_dev = dev->se_sub_dev;  		atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt);  		smp_mb__after_atomic_inc();  		spin_unlock(&lu_gp->lu_gp_lock); -		spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +		spin_lock(&dev->t10_alua.tg_pt_gps_lock);  		list_for_each_entry(tg_pt_gp, -				&su_dev->t10_alua.tg_pt_gps_list, +				&dev->t10_alua.tg_pt_gps_list,  				tg_pt_gp_list) {  			if (!tg_pt_gp->tg_pt_gp_valid_id) @@ -981,7 +975,7 @@ int core_alua_do_port_transition(  			}  			atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);  			smp_mb__after_atomic_inc(); -			spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  			/*  			 * core_alua_do_transition_tg_pt() will always return  			 * success. @@ -989,11 +983,11 @@ int core_alua_do_port_transition(  			core_alua_do_transition_tg_pt(tg_pt_gp, port,  					nacl, md_buf, new_state, explict); -			spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +			spin_lock(&dev->t10_alua.tg_pt_gps_lock);  			atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);  			smp_mb__after_atomic_dec();  		} -		spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  		spin_lock(&lu_gp->lu_gp_lock);  		atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt); @@ -1268,14 +1262,9 @@ void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp)  void core_alua_free_lu_gp_mem(struct se_device *dev)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev; -	struct t10_alua *alua = &su_dev->t10_alua;  	struct t10_alua_lu_gp *lu_gp;  	struct t10_alua_lu_gp_member *lu_gp_mem; -	if (alua->alua_type != SPC3_ALUA_EMULATED) -		return; -  	lu_gp_mem = dev->dev_alua_lu_gp_mem;  	if (!lu_gp_mem)  		return; @@ -1358,10 +1347,8 @@ void __core_alua_drop_lu_gp_mem(  	spin_unlock(&lu_gp->lu_gp_lock);  } -struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( -	struct se_subsystem_dev *su_dev, -	const char *name, -	int def_group) +struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, +		const char *name, int def_group)  {  	struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -1375,7 +1362,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(  	mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex);  	spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);  	atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); -	tg_pt_gp->tg_pt_gp_su_dev = su_dev; +	tg_pt_gp->tg_pt_gp_dev = dev;  	tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN;  	atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,  		ALUA_ACCESS_STATE_ACTIVE_OPTMIZED); @@ -1392,14 +1379,14 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(  	tg_pt_gp->tg_pt_gp_implict_trans_secs = ALUA_DEFAULT_IMPLICT_TRANS_SECS;  	if (def_group) { -		spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +		spin_lock(&dev->t10_alua.tg_pt_gps_lock);  		tg_pt_gp->tg_pt_gp_id = -				su_dev->t10_alua.alua_tg_pt_gps_counter++; +				dev->t10_alua.alua_tg_pt_gps_counter++;  		tg_pt_gp->tg_pt_gp_valid_id = 1; -		su_dev->t10_alua.alua_tg_pt_gps_count++; +		dev->t10_alua.alua_tg_pt_gps_count++;  		list_add_tail(&tg_pt_gp->tg_pt_gp_list, -			      &su_dev->t10_alua.tg_pt_gps_list); -		spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +			      &dev->t10_alua.tg_pt_gps_list); +		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  	}  	return tg_pt_gp; @@ -1409,9 +1396,10 @@ int core_alua_set_tg_pt_gp_id(  	struct t10_alua_tg_pt_gp *tg_pt_gp,  	u16 tg_pt_gp_id)  { -	struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; +	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;  	struct t10_alua_tg_pt_gp *tg_pt_gp_tmp;  	u16 tg_pt_gp_id_tmp; +  	/*  	 * The tg_pt_gp->tg_pt_gp_id may only be set once..  	 */ @@ -1421,19 +1409,19 @@ int core_alua_set_tg_pt_gp_id(  		return -EINVAL;  	} -	spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); -	if (su_dev->t10_alua.alua_tg_pt_gps_count == 0x0000ffff) { +	spin_lock(&dev->t10_alua.tg_pt_gps_lock); +	if (dev->t10_alua.alua_tg_pt_gps_count == 0x0000ffff) {  		pr_err("Maximum ALUA alua_tg_pt_gps_count:"  			" 0x0000ffff reached\n"); -		spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  		kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);  		return -ENOSPC;  	}  again:  	tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id : -			su_dev->t10_alua.alua_tg_pt_gps_counter++; +			dev->t10_alua.alua_tg_pt_gps_counter++; -	list_for_each_entry(tg_pt_gp_tmp, &su_dev->t10_alua.tg_pt_gps_list, +	list_for_each_entry(tg_pt_gp_tmp, &dev->t10_alua.tg_pt_gps_list,  			tg_pt_gp_list) {  		if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) {  			if (!tg_pt_gp_id) @@ -1441,7 +1429,7 @@ again:  			pr_err("ALUA Target Port Group ID: %hu already"  				" exists, ignoring request\n", tg_pt_gp_id); -			spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  			return -EINVAL;  		}  	} @@ -1449,9 +1437,9 @@ again:  	tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp;  	tg_pt_gp->tg_pt_gp_valid_id = 1;  	list_add_tail(&tg_pt_gp->tg_pt_gp_list, -			&su_dev->t10_alua.tg_pt_gps_list); -	su_dev->t10_alua.alua_tg_pt_gps_count++; -	spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +			&dev->t10_alua.tg_pt_gps_list); +	dev->t10_alua.alua_tg_pt_gps_count++; +	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  	return 0;  } @@ -1480,8 +1468,9 @@ struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(  void core_alua_free_tg_pt_gp(  	struct t10_alua_tg_pt_gp *tg_pt_gp)  { -	struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; +	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp; +  	/*  	 * Once we have reached this point, config_item_put() has already  	 * been called from target_core_alua_drop_tg_pt_gp(). @@ -1490,10 +1479,11 @@ void core_alua_free_tg_pt_gp(  	 * no assications *OR* explict ALUA via SET_TARGET_PORT_GROUPS  	 * can be made while we are releasing struct t10_alua_tg_pt_gp.  	 */ -	spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +	spin_lock(&dev->t10_alua.tg_pt_gps_lock);  	list_del(&tg_pt_gp->tg_pt_gp_list); -	su_dev->t10_alua.alua_tg_pt_gps_counter--; -	spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +	dev->t10_alua.alua_tg_pt_gps_counter--; +	spin_unlock(&dev->t10_alua.tg_pt_gps_lock); +  	/*  	 * Allow a struct t10_alua_tg_pt_gp_member * referenced by  	 * core_alua_get_tg_pt_gp_by_name() in @@ -1502,6 +1492,7 @@ void core_alua_free_tg_pt_gp(  	 */  	while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt))  		cpu_relax(); +  	/*  	 * Release reference to struct t10_alua_tg_pt_gp from all associated  	 * struct se_port. @@ -1525,9 +1516,9 @@ void core_alua_free_tg_pt_gp(  		 * default_tg_pt_gp.  		 */  		spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); -		if (tg_pt_gp != su_dev->t10_alua.default_tg_pt_gp) { +		if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) {  			__core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, -					su_dev->t10_alua.default_tg_pt_gp); +					dev->t10_alua.default_tg_pt_gp);  		} else  			tg_pt_gp_mem->tg_pt_gp = NULL;  		spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); @@ -1541,14 +1532,9 @@ void core_alua_free_tg_pt_gp(  void core_alua_free_tg_pt_gp_mem(struct se_port *port)  { -	struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; -	struct t10_alua *alua = &su_dev->t10_alua;  	struct t10_alua_tg_pt_gp *tg_pt_gp;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; -	if (alua->alua_type != SPC3_ALUA_EMULATED) -		return; -  	tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;  	if (!tg_pt_gp_mem)  		return; @@ -1574,25 +1560,24 @@ void core_alua_free_tg_pt_gp_mem(struct se_port *port)  }  static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( -	struct se_subsystem_dev *su_dev, -	const char *name) +		struct se_device *dev, const char *name)  {  	struct t10_alua_tg_pt_gp *tg_pt_gp;  	struct config_item *ci; -	spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); -	list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list, +	spin_lock(&dev->t10_alua.tg_pt_gps_lock); +	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,  			tg_pt_gp_list) {  		if (!tg_pt_gp->tg_pt_gp_valid_id)  			continue;  		ci = &tg_pt_gp->tg_pt_gp_group.cg_item;  		if (!strcmp(config_item_name(ci), name)) {  			atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); -			spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  			return tg_pt_gp;  		}  	} -	spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  	return NULL;  } @@ -1600,11 +1585,11 @@ static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name(  static void core_alua_put_tg_pt_gp_from_name(  	struct t10_alua_tg_pt_gp *tg_pt_gp)  { -	struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; +	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; -	spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); +	spin_lock(&dev->t10_alua.tg_pt_gps_lock);  	atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); -	spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); +	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);  }  /* @@ -1640,16 +1625,11 @@ static void __core_alua_drop_tg_pt_gp_mem(  ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page)  { -	struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;  	struct config_item *tg_pt_ci; -	struct t10_alua *alua = &su_dev->t10_alua;  	struct t10_alua_tg_pt_gp *tg_pt_gp;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;  	ssize_t len = 0; -	if (alua->alua_type != SPC3_ALUA_EMULATED) -		return len; -  	tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;  	if (!tg_pt_gp_mem)  		return len; @@ -1683,7 +1663,7 @@ ssize_t core_alua_store_tg_pt_gp_info(  {  	struct se_portal_group *tpg;  	struct se_lun *lun; -	struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; +	struct se_device *dev = port->sep_lun->lun_se_dev;  	struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;  	unsigned char buf[TG_PT_GROUP_NAME_BUF]; @@ -1692,13 +1672,9 @@ ssize_t core_alua_store_tg_pt_gp_info(  	tpg = port->sep_tpg;  	lun = port->sep_lun; -	if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) { -		pr_warn("SPC3_ALUA_EMULATED not enabled for" -			" %s/tpgt_%hu/%s\n", tpg->se_tpg_tfo->tpg_get_wwn(tpg), -			tpg->se_tpg_tfo->tpg_get_tag(tpg), -			config_item_name(&lun->lun_group.cg_item)); -		return -EINVAL; -	} +	tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; +	if (!tg_pt_gp_mem) +		return 0;  	if (count > TG_PT_GROUP_NAME_BUF) {  		pr_err("ALUA Target Port Group alias too large!\n"); @@ -1716,18 +1692,11 @@ ssize_t core_alua_store_tg_pt_gp_info(  		 * struct t10_alua_tg_pt_gp.  This reference is released with  		 * core_alua_put_tg_pt_gp_from_name() below.  		 */ -		tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(su_dev, +		tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(dev,  					strstrip(buf));  		if (!tg_pt_gp_new)  			return -ENODEV;  	} -	tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; -	if (!tg_pt_gp_mem) { -		if (tg_pt_gp_new) -			core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new); -		pr_err("NULL struct se_port->sep_alua_tg_pt_gp_mem pointer\n"); -		return -EINVAL; -	}  	spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);  	tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; @@ -1750,7 +1719,7 @@ ssize_t core_alua_store_tg_pt_gp_info(  			__core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);  			__core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, -					su_dev->t10_alua.default_tg_pt_gp); +					dev->t10_alua.default_tg_pt_gp);  			spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);  			return count; @@ -2054,32 +2023,12 @@ ssize_t core_alua_store_secondary_write_metadata(  	return count;  } -int core_setup_alua(struct se_device *dev, int force_pt) +int core_setup_alua(struct se_device *dev)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev; -	struct t10_alua *alua = &su_dev->t10_alua; -	struct t10_alua_lu_gp_member *lu_gp_mem; -	/* -	 * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic -	 * of the Underlying SCSI hardware.  In Linux/SCSI terms, this can -	 * cause a problem because libata and some SATA RAID HBAs appear -	 * under Linux/SCSI, but emulate SCSI logic themselves. -	 */ -	if (((dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && -	    !(dev->se_sub_dev->se_dev_attrib.emulate_alua)) || force_pt) { -		alua->alua_type = SPC_ALUA_PASSTHROUGH; -		alua->alua_state_check = &core_alua_state_check_nop; -		pr_debug("%s: Using SPC_ALUA_PASSTHROUGH, no ALUA" -			" emulation\n", dev->transport->name); -		return 0; -	} -	/* -	 * If SPC-3 or above is reported by real or emulated struct se_device, -	 * use emulated ALUA. -	 */ -	if (dev->transport->get_device_rev(dev) >= SCSI_3) { -		pr_debug("%s: Enabling ALUA Emulation for SPC-3" -			" device\n", dev->transport->name); +	if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV && +	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { +		struct t10_alua_lu_gp_member *lu_gp_mem; +  		/*  		 * Associate this struct se_device with the default ALUA  		 * LUN Group. @@ -2088,8 +2037,6 @@ int core_setup_alua(struct se_device *dev, int force_pt)  		if (IS_ERR(lu_gp_mem))  			return PTR_ERR(lu_gp_mem); -		alua->alua_type = SPC3_ALUA_EMULATED; -		alua->alua_state_check = &core_alua_state_check;  		spin_lock(&lu_gp_mem->lu_gp_mem_lock);  		__core_alua_attach_lu_gp_mem(lu_gp_mem,  				default_lu_gp); @@ -2098,11 +2045,6 @@ int core_setup_alua(struct se_device *dev, int force_pt)  		pr_debug("%s: Adding to default ALUA LU Group:"  			" core/alua/lu_gps/default_lu_gp\n",  			dev->transport->name); -	} else { -		alua->alua_type = SPC2_ALUA_DISABLED; -		alua->alua_state_check = &core_alua_state_check_nop; -		pr_debug("%s: Disabling ALUA Emulation for SPC-2" -			" device\n", dev->transport->name);  	}  	return 0; diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index f920c170d47b..e539c3e7f4ad 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -72,8 +72,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache;  extern struct kmem_cache *t10_alua_tg_pt_gp_cache;  extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -extern int target_emulate_report_target_port_groups(struct se_cmd *); -extern int target_emulate_set_target_port_groups(struct se_cmd *); +extern sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *); +extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *);  extern int core_alua_check_nonop_delay(struct se_cmd *);  extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,  				struct se_device *, struct se_port *, @@ -91,7 +91,7 @@ extern void __core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member *,  					struct t10_alua_lu_gp *);  extern void core_alua_drop_lu_gp_dev(struct se_device *);  extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( -			struct se_subsystem_dev *, const char *, int); +			struct se_device *, const char *, int);  extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16);  extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(  					struct se_port *); @@ -131,6 +131,7 @@ extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun *,  					char *);  extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun *,  					const char *, size_t); -extern int core_setup_alua(struct se_device *, int); +extern int core_setup_alua(struct se_device *); +extern sense_reason_t target_alua_state_check(struct se_cmd *cmd);  #endif /* TARGET_CORE_ALUA_H */ diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index c123327499a3..4efb61b8d001 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3,8 +3,7 @@   *   * This file contains ConfigFS logic for the Generic Target Engine project.   * - * Copyright (c) 2008-2011 Rising Tide Systems - * Copyright (c) 2008-2011 Linux-iSCSI.org + * (c) Copyright 2008-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -565,21 +564,8 @@ static ssize_t target_core_dev_show_attr_##_name(			\  	struct se_dev_attrib *da,					\  	char *page)							\  {									\ -	struct se_device *dev;						\ -	struct se_subsystem_dev *se_dev = da->da_sub_dev;			\ -	ssize_t rb;							\ -									\ -	spin_lock(&se_dev->se_dev_lock);				\ -	dev = se_dev->se_dev_ptr;					\ -	if (!dev) {							\ -		spin_unlock(&se_dev->se_dev_lock); 			\ -		return -ENODEV;						\ -	}								\ -	rb = snprintf(page, PAGE_SIZE, "%u\n",				\ -		(u32)dev->se_sub_dev->se_dev_attrib._name);		\ -	spin_unlock(&se_dev->se_dev_lock);				\ -									\ -	return rb;							\ +	return snprintf(page, PAGE_SIZE, "%u\n",			\ +		(u32)da->da_dev->dev_attrib._name);			\  }  #define DEF_DEV_ATTRIB_STORE(_name)					\ @@ -588,26 +574,16 @@ static ssize_t target_core_dev_store_attr_##_name(			\  	const char *page,						\  	size_t count)							\  {									\ -	struct se_device *dev;						\ -	struct se_subsystem_dev *se_dev = da->da_sub_dev;			\  	unsigned long val;						\  	int ret;							\  									\ -	spin_lock(&se_dev->se_dev_lock);				\ -	dev = se_dev->se_dev_ptr;					\ -	if (!dev) {							\ -		spin_unlock(&se_dev->se_dev_lock);			\ -		return -ENODEV;						\ -	}								\  	ret = strict_strtoul(page, 0, &val);				\  	if (ret < 0) {							\ -		spin_unlock(&se_dev->se_dev_lock);                      \  		pr_err("strict_strtoul() failed with"		\  			" ret: %d\n", ret);				\  		return -EINVAL;						\  	}								\ -	ret = se_dev_set_##_name(dev, (u32)val);			\ -	spin_unlock(&se_dev->se_dev_lock);				\ +	ret = se_dev_set_##_name(da->da_dev, (u32)val);			\  									\  	return (!ret) ? count : -EINVAL;				\  } @@ -699,6 +675,9 @@ SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR);  DEF_DEV_ATTRIB(unmap_granularity_alignment);  SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR); +DEF_DEV_ATTRIB(max_write_same_len); +SE_DEV_ATTR(max_write_same_len, S_IRUGO | S_IWUSR); +  CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);  static struct configfs_attribute *target_core_dev_attrib_attrs[] = { @@ -724,6 +703,7 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {  	&target_core_dev_attrib_max_unmap_block_desc_count.attr,  	&target_core_dev_attrib_unmap_granularity.attr,  	&target_core_dev_attrib_unmap_granularity_alignment.attr, +	&target_core_dev_attrib_max_write_same_len.attr,  	NULL,  }; @@ -764,13 +744,6 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial(  	struct t10_wwn *t10_wwn,  	char *page)  { -	struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; -	struct se_device *dev; - -	dev = se_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; -  	return sprintf(page, "T10 VPD Unit Serial Number: %s\n",  		&t10_wwn->unit_serial[0]);  } @@ -780,8 +753,7 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(  	const char *page,  	size_t count)  { -	struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev; -	struct se_device *dev; +	struct se_device *dev = t10_wwn->t10_dev;  	unsigned char buf[INQUIRY_VPD_SERIAL_LEN];  	/* @@ -794,7 +766,7 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(  	 * it is doing 'the right thing' wrt a world wide unique  	 * VPD Unit Serial Number that OS dependent multipath can depend on.  	 */ -	if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) { +	if (dev->dev_flags & DF_FIRMWARE_VPD_UNIT_SERIAL) {  		pr_err("Underlying SCSI device firmware provided VPD"  			" Unit Serial, ignoring request\n");  		return -EOPNOTSUPP; @@ -811,15 +783,13 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(  	 * (underneath the initiator side OS dependent multipath code)  	 * could cause negative effects.  	 */ -	dev = su_dev->se_dev_ptr; -	if (dev) { -		if (atomic_read(&dev->dev_export_obj.obj_access_count)) { -			pr_err("Unable to set VPD Unit Serial while" -				" active %d $FABRIC_MOD exports exist\n", -				atomic_read(&dev->dev_export_obj.obj_access_count)); -			return -EINVAL; -		} +	if (dev->export_count) { +		pr_err("Unable to set VPD Unit Serial while" +			" active %d $FABRIC_MOD exports exist\n", +			dev->export_count); +		return -EINVAL;  	} +  	/*  	 * This currently assumes ASCII encoding for emulated VPD Unit Serial.  	 * @@ -828,12 +798,12 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(  	 */  	memset(buf, 0, INQUIRY_VPD_SERIAL_LEN);  	snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page); -	snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN, +	snprintf(dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN,  			"%s", strstrip(buf)); -	su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL; +	dev->dev_flags |= DF_EMULATED_VPD_UNIT_SERIAL;  	pr_debug("Target_Core_ConfigFS: Set emulated VPD Unit Serial:" -			" %s\n", su_dev->t10_wwn.unit_serial); +			" %s\n", dev->t10_wwn.unit_serial);  	return count;  } @@ -847,16 +817,10 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier(  	struct t10_wwn *t10_wwn,  	char *page)  { -	struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; -	struct se_device *dev;  	struct t10_vpd *vpd;  	unsigned char buf[VPD_TMP_BUF_SIZE];  	ssize_t len = 0; -	dev = se_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; -  	memset(buf, 0, VPD_TMP_BUF_SIZE);  	spin_lock(&t10_wwn->t10_vpd_lock); @@ -894,16 +858,10 @@ static ssize_t target_core_dev_wwn_show_attr_##_name(			\  	struct t10_wwn *t10_wwn,					\  	char *page)							\  {									\ -	struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev;		\ -	struct se_device *dev;						\  	struct t10_vpd *vpd;							\  	unsigned char buf[VPD_TMP_BUF_SIZE];				\  	ssize_t len = 0;						\  									\ -	dev = se_dev->se_dev_ptr;					\ -	if (!dev)							\ -		return -ENODEV;						\ -									\  	spin_lock(&t10_wwn->t10_vpd_lock);				\  	list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) {	\  		if (vpd->association != _assoc)				\ @@ -1003,7 +961,7 @@ static struct config_item_type target_core_dev_wwn_cit = {  /*  Start functions for struct config_item_type target_core_dev_pr_cit */ -CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev); +CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_device);  #define SE_DEV_PR_ATTR(_name, _mode)					\  static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \  	__CONFIGFS_EATTR(_name, _mode,					\ @@ -1015,13 +973,8 @@ static struct target_core_dev_pr_attribute target_core_dev_pr_##_name =	\  	__CONFIGFS_EATTR_RO(_name,					\  	target_core_dev_pr_show_attr_##_name); -/* - * res_holder - */ -static ssize_t target_core_dev_pr_show_spc3_res( -	struct se_device *dev, -	char *page, -	ssize_t *len) +static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev, +		char *page)  {  	struct se_node_acl *se_nacl;  	struct t10_pr_registration *pr_reg; @@ -1030,134 +983,82 @@ static ssize_t target_core_dev_pr_show_spc3_res(  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); -	spin_lock(&dev->dev_reservation_lock);  	pr_reg = dev->dev_pr_res_holder; -	if (!pr_reg) { -		*len += sprintf(page + *len, "No SPC-3 Reservation holder\n"); -		spin_unlock(&dev->dev_reservation_lock); -		return *len; -	} +	if (!pr_reg) +		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); -	*len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n", +	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] : ""); -	spin_unlock(&dev->dev_reservation_lock); - -	return *len;  } -static ssize_t target_core_dev_pr_show_spc2_res( -	struct se_device *dev, -	char *page, -	ssize_t *len) +static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev, +		char *page)  {  	struct se_node_acl *se_nacl; +	ssize_t len; -	spin_lock(&dev->dev_reservation_lock);  	se_nacl = dev->dev_reserved_node_acl; -	if (!se_nacl) { -		*len += sprintf(page + *len, "No SPC-2 Reservation holder\n"); -		spin_unlock(&dev->dev_reservation_lock); -		return *len; +	if (se_nacl) { +		len = sprintf(page, +			      "SPC-2 Reservation: %s Initiator: %s\n", +			      se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), +			      se_nacl->initiatorname); +	} else { +		len = sprintf(page, "No SPC-2 Reservation holder\n");  	} -	*len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n", -		se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), -		se_nacl->initiatorname); -	spin_unlock(&dev->dev_reservation_lock); - -	return *len; +	return len;  } -static ssize_t target_core_dev_pr_show_attr_res_holder( -	struct se_subsystem_dev *su_dev, -	char *page) +static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev, +		char *page)  { -	ssize_t len = 0; +	int ret; -	if (!su_dev->se_dev_ptr) -		return -ENODEV; - -	switch (su_dev->t10_pr.res_type) { -	case SPC3_PERSISTENT_RESERVATIONS: -		target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr, -				page, &len); -		break; -	case SPC2_RESERVATIONS: -		target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr, -				page, &len); -		break; -	case SPC_PASSTHROUGH: -		len += sprintf(page+len, "Passthrough\n"); -		break; -	default: -		len += sprintf(page+len, "Unknown\n"); -		break; -	} +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) +		return sprintf(page, "Passthrough\n"); -	return len; +	spin_lock(&dev->dev_reservation_lock); +	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) +		ret = target_core_dev_pr_show_spc2_res(dev, page); +	else +		ret = target_core_dev_pr_show_spc3_res(dev, page); +	spin_unlock(&dev->dev_reservation_lock); +	return ret;  }  SE_DEV_PR_ATTR_RO(res_holder); -/* - * res_pr_all_tgt_pts - */  static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	struct se_device *dev; -	struct t10_pr_registration *pr_reg;  	ssize_t len = 0; -	dev = su_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) -		return len; -  	spin_lock(&dev->dev_reservation_lock); -	pr_reg = dev->dev_pr_res_holder; -	if (!pr_reg) { +	if (!dev->dev_pr_res_holder) {  		len = sprintf(page, "No SPC-3 Reservation holder\n"); -		spin_unlock(&dev->dev_reservation_lock); -		return len; -	} -	/* -	 * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3 -	 * Basic PERSISTENT RESERVER OUT parameter list, page 290 -	 */ -	if (pr_reg->pr_reg_all_tg_pt) +	} else if (dev->dev_pr_res_holder->pr_reg_all_tg_pt) {  		len = sprintf(page, "SPC-3 Reservation: All Target"  			" Ports registration\n"); -	else +	} else {  		len = sprintf(page, "SPC-3 Reservation: Single"  			" Target Port registration\n"); -	spin_unlock(&dev->dev_reservation_lock); +	} +	spin_unlock(&dev->dev_reservation_lock);  	return len;  }  SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts); -/* - * res_pr_generation - */  static ssize_t target_core_dev_pr_show_attr_res_pr_generation( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	if (!su_dev->se_dev_ptr) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) -		return 0; - -	return sprintf(page, "0x%08x\n", su_dev->t10_pr.pr_generation); +	return sprintf(page, "0x%08x\n", dev->t10_pr.pr_generation);  }  SE_DEV_PR_ATTR_RO(res_pr_generation); @@ -1166,10 +1067,8 @@ SE_DEV_PR_ATTR_RO(res_pr_generation);   * res_pr_holder_tg_port   */  static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	struct se_device *dev;  	struct se_node_acl *se_nacl;  	struct se_lun *lun;  	struct se_portal_group *se_tpg; @@ -1177,20 +1076,13 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(  	struct target_core_fabric_ops *tfo;  	ssize_t len = 0; -	dev = su_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) -		return len; -  	spin_lock(&dev->dev_reservation_lock);  	pr_reg = dev->dev_pr_res_holder;  	if (!pr_reg) {  		len = sprintf(page, "No SPC-3 Reservation holder\n"); -		spin_unlock(&dev->dev_reservation_lock); -		return len; +		goto out_unlock;  	} +  	se_nacl = pr_reg->pr_reg_nacl;  	se_tpg = se_nacl->se_tpg;  	lun = pr_reg->pr_reg_tg_pt_lun; @@ -1204,19 +1096,16 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(  		" %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi,  		tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg),  		tfo->get_fabric_name(), lun->unpacked_lun); -	spin_unlock(&dev->dev_reservation_lock); +out_unlock: +	spin_unlock(&dev->dev_reservation_lock);  	return len;  }  SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); -/* - * res_pr_registered_i_pts - */  static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  {  	struct target_core_fabric_ops *tfo;  	struct t10_pr_registration *pr_reg; @@ -1225,16 +1114,10 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(  	ssize_t len = 0;  	int reg_count = 0, prf_isid; -	if (!su_dev->se_dev_ptr) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) -		return len; -  	len += sprintf(page+len, "SPC-3 PR Registrations:\n"); -	spin_lock(&su_dev->t10_pr.registration_lock); -	list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, +	spin_lock(&dev->t10_pr.registration_lock); +	list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,  			pr_reg_list) {  		memset(buf, 0, 384); @@ -1254,7 +1137,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(  		len += sprintf(page+len, "%s", buf);  		reg_count++;  	} -	spin_unlock(&su_dev->t10_pr.registration_lock); +	spin_unlock(&dev->t10_pr.registration_lock);  	if (!reg_count)  		len += sprintf(page+len, "None\n"); @@ -1264,88 +1147,48 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(  SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts); -/* - * res_pr_type - */  static ssize_t target_core_dev_pr_show_attr_res_pr_type( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	struct se_device *dev;  	struct t10_pr_registration *pr_reg;  	ssize_t len = 0; -	dev = su_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) -		return len; -  	spin_lock(&dev->dev_reservation_lock);  	pr_reg = dev->dev_pr_res_holder; -	if (!pr_reg) { +	if (pr_reg) { +		len = sprintf(page, "SPC-3 Reservation Type: %s\n", +			core_scsi3_pr_dump_type(pr_reg->pr_res_type)); +	} else {  		len = sprintf(page, "No SPC-3 Reservation holder\n"); -		spin_unlock(&dev->dev_reservation_lock); -		return len;  	} -	len = sprintf(page, "SPC-3 Reservation Type: %s\n", -		core_scsi3_pr_dump_type(pr_reg->pr_res_type)); -	spin_unlock(&dev->dev_reservation_lock); +	spin_unlock(&dev->dev_reservation_lock);  	return len;  }  SE_DEV_PR_ATTR_RO(res_pr_type); -/* - * res_type - */  static ssize_t target_core_dev_pr_show_attr_res_type( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	ssize_t len = 0; - -	if (!su_dev->se_dev_ptr) -		return -ENODEV; - -	switch (su_dev->t10_pr.res_type) { -	case SPC3_PERSISTENT_RESERVATIONS: -		len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); -		break; -	case SPC2_RESERVATIONS: -		len = sprintf(page, "SPC2_RESERVATIONS\n"); -		break; -	case SPC_PASSTHROUGH: -		len = sprintf(page, "SPC_PASSTHROUGH\n"); -		break; -	default: -		len = sprintf(page, "UNKNOWN\n"); -		break; -	} - -	return len; +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) +		return sprintf(page, "SPC_PASSTHROUGH\n"); +	else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) +		return sprintf(page, "SPC2_RESERVATIONS\n"); +	else +		return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n");  }  SE_DEV_PR_ATTR_RO(res_type); -/* - * res_aptpl_active - */ -  static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	if (!su_dev->se_dev_ptr) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)  		return 0;  	return sprintf(page, "APTPL Bit Status: %s\n", -		(su_dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled"); +		(dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled");  }  SE_DEV_PR_ATTR_RO(res_aptpl_active); @@ -1354,13 +1197,9 @@ SE_DEV_PR_ATTR_RO(res_aptpl_active);   * res_aptpl_metadata   */  static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( -	struct se_subsystem_dev *su_dev, -	char *page) +		struct se_device *dev, char *page)  { -	if (!su_dev->se_dev_ptr) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)  		return 0;  	return sprintf(page, "Ready to process PR APTPL metadata..\n"); @@ -1392,11 +1231,10 @@ static match_table_t tokens = {  };  static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( -	struct se_subsystem_dev *su_dev, +	struct se_device *dev,  	const char *page,  	size_t count)  { -	struct se_device *dev;  	unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL;  	unsigned char *t_fabric = NULL, *t_port = NULL;  	char *orig, *ptr, *arg_p, *opts; @@ -1408,14 +1246,12 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(  	u16 port_rpti = 0, tpgt = 0;  	u8 type = 0, scope; -	dev = su_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; - -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) +		return 0; +	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)  		return 0; -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_debug("Unable to process APTPL metadata while"  			" active fabric exports exist\n");  		return -EINVAL; @@ -1558,7 +1394,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(  		goto out;  	} -	ret = core_scsi3_alloc_aptpl_registration(&su_dev->t10_pr, sa_res_key, +	ret = core_scsi3_alloc_aptpl_registration(&dev->t10_pr, sa_res_key,  			i_port, isid, mapped_lun, t_port, tpgt, target_lun,  			res_holder, all_tg_pt, type);  out: @@ -1573,7 +1409,7 @@ out:  SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR); -CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group); +CONFIGFS_EATTR_OPS(target_core_dev_pr, se_device, dev_pr_group);  static struct configfs_attribute *target_core_dev_pr_attrs[] = {  	&target_core_dev_pr_res_holder.attr, @@ -1605,18 +1441,14 @@ static struct config_item_type target_core_dev_pr_cit = {  static ssize_t target_core_show_dev_info(void *p, char *page)  { -	struct se_subsystem_dev *se_dev = p; -	struct se_hba *hba = se_dev->se_dev_hba; -	struct se_subsystem_api *t = hba->transport; +	struct se_device *dev = p; +	struct se_subsystem_api *t = dev->transport;  	int bl = 0;  	ssize_t read_bytes = 0; -	if (!se_dev->se_dev_ptr) -		return -ENODEV; - -	transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl); +	transport_dump_dev_state(dev, page, &bl);  	read_bytes += bl; -	read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes); +	read_bytes += t->show_configfs_dev_params(dev, page+read_bytes);  	return read_bytes;  } @@ -1633,17 +1465,10 @@ static ssize_t target_core_store_dev_control(  	const char *page,  	size_t count)  { -	struct se_subsystem_dev *se_dev = p; -	struct se_hba *hba = se_dev->se_dev_hba; -	struct se_subsystem_api *t = hba->transport; +	struct se_device *dev = p; +	struct se_subsystem_api *t = dev->transport; -	if (!se_dev->se_dev_su_ptr) { -		pr_err("Unable to locate struct se_subsystem_dev>se" -				"_dev_su_ptr\n"); -		return -EINVAL; -	} - -	return t->set_configfs_dev_params(hba, se_dev, page, count); +	return t->set_configfs_dev_params(dev, page, count);  }  static struct target_core_configfs_attribute target_core_attr_dev_control = { @@ -1656,12 +1481,12 @@ static struct target_core_configfs_attribute target_core_attr_dev_control = {  static ssize_t target_core_show_dev_alias(void *p, char *page)  { -	struct se_subsystem_dev *se_dev = p; +	struct se_device *dev = p; -	if (!(se_dev->su_dev_flags & SDF_USING_ALIAS)) +	if (!(dev->dev_flags & DF_USING_ALIAS))  		return 0; -	return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias); +	return snprintf(page, PAGE_SIZE, "%s\n", dev->dev_alias);  }  static ssize_t target_core_store_dev_alias( @@ -1669,8 +1494,8 @@ static ssize_t target_core_store_dev_alias(  	const char *page,  	size_t count)  { -	struct se_subsystem_dev *se_dev = p; -	struct se_hba *hba = se_dev->se_dev_hba; +	struct se_device *dev = p; +	struct se_hba *hba = dev->se_hba;  	ssize_t read_bytes;  	if (count > (SE_DEV_ALIAS_LEN-1)) { @@ -1680,19 +1505,18 @@ static ssize_t target_core_store_dev_alias(  		return -EINVAL;  	} -	read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, -			"%s", page); +	read_bytes = snprintf(&dev->dev_alias[0], SE_DEV_ALIAS_LEN, "%s", page);  	if (!read_bytes)  		return -EINVAL; -	if (se_dev->se_dev_alias[read_bytes - 1] == '\n') -		se_dev->se_dev_alias[read_bytes - 1] = '\0'; +	if (dev->dev_alias[read_bytes - 1] == '\n') +		dev->dev_alias[read_bytes - 1] = '\0'; -	se_dev->su_dev_flags |= SDF_USING_ALIAS; +	dev->dev_flags |= DF_USING_ALIAS;  	pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n",  		config_item_name(&hba->hba_group.cg_item), -		config_item_name(&se_dev->se_dev_group.cg_item), -		se_dev->se_dev_alias); +		config_item_name(&dev->dev_group.cg_item), +		dev->dev_alias);  	return read_bytes;  } @@ -1707,12 +1531,12 @@ static struct target_core_configfs_attribute target_core_attr_dev_alias = {  static ssize_t target_core_show_dev_udev_path(void *p, char *page)  { -	struct se_subsystem_dev *se_dev = p; +	struct se_device *dev = p; -	if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) +	if (!(dev->dev_flags & DF_USING_UDEV_PATH))  		return 0; -	return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path); +	return snprintf(page, PAGE_SIZE, "%s\n", dev->udev_path);  }  static ssize_t target_core_store_dev_udev_path( @@ -1720,8 +1544,8 @@ static ssize_t target_core_store_dev_udev_path(  	const char *page,  	size_t count)  { -	struct se_subsystem_dev *se_dev = p; -	struct se_hba *hba = se_dev->se_dev_hba; +	struct se_device *dev = p; +	struct se_hba *hba = dev->se_hba;  	ssize_t read_bytes;  	if (count > (SE_UDEV_PATH_LEN-1)) { @@ -1731,19 +1555,19 @@ static ssize_t target_core_store_dev_udev_path(  		return -EINVAL;  	} -	read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, +	read_bytes = snprintf(&dev->udev_path[0], SE_UDEV_PATH_LEN,  			"%s", page);  	if (!read_bytes)  		return -EINVAL; -	if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n') -		se_dev->se_dev_udev_path[read_bytes - 1] = '\0'; +	if (dev->udev_path[read_bytes - 1] == '\n') +		dev->udev_path[read_bytes - 1] = '\0'; -	se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; +	dev->dev_flags |= DF_USING_UDEV_PATH;  	pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n",  		config_item_name(&hba->hba_group.cg_item), -		config_item_name(&se_dev->se_dev_group.cg_item), -		se_dev->se_dev_udev_path); +		config_item_name(&dev->dev_group.cg_item), +		dev->udev_path);  	return read_bytes;  } @@ -1761,11 +1585,9 @@ static ssize_t target_core_store_dev_enable(  	const char *page,  	size_t count)  { -	struct se_subsystem_dev *se_dev = p; -	struct se_device *dev; -	struct se_hba *hba = se_dev->se_dev_hba; -	struct se_subsystem_api *t = hba->transport; +	struct se_device *dev = p;  	char *ptr; +	int ret;  	ptr = strstr(page, "1");  	if (!ptr) { @@ -1773,25 +1595,10 @@ static ssize_t target_core_store_dev_enable(  				" is \"1\"\n");  		return -EINVAL;  	} -	if (se_dev->se_dev_ptr) { -		pr_err("se_dev->se_dev_ptr already set for storage" -				" object\n"); -		return -EEXIST; -	} - -	if (t->check_configfs_dev_params(hba, se_dev) < 0) -		return -EINVAL; - -	dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); -	if (IS_ERR(dev)) -		return PTR_ERR(dev); -	else if (!dev) -		return -EINVAL; - -	se_dev->se_dev_ptr = dev; -	pr_debug("Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:" -		" %p\n", se_dev->se_dev_ptr); +	ret = target_configure_device(dev); +	if (ret) +		return ret;  	return count;  } @@ -1805,26 +1612,15 @@ static struct target_core_configfs_attribute target_core_attr_dev_enable = {  static ssize_t target_core_show_alua_lu_gp(void *p, char *page)  { -	struct se_device *dev; -	struct se_subsystem_dev *su_dev = p; +	struct se_device *dev = p;  	struct config_item *lu_ci;  	struct t10_alua_lu_gp *lu_gp;  	struct t10_alua_lu_gp_member *lu_gp_mem;  	ssize_t len = 0; -	dev = su_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; - -	if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) -		return len; -  	lu_gp_mem = dev->dev_alua_lu_gp_mem; -	if (!lu_gp_mem) { -		pr_err("NULL struct se_device->dev_alua_lu_gp_mem" -				" pointer\n"); -		return -EINVAL; -	} +	if (!lu_gp_mem) +		return 0;  	spin_lock(&lu_gp_mem->lu_gp_mem_lock);  	lu_gp = lu_gp_mem->lu_gp; @@ -1843,24 +1639,17 @@ static ssize_t target_core_store_alua_lu_gp(  	const char *page,  	size_t count)  { -	struct se_device *dev; -	struct se_subsystem_dev *su_dev = p; -	struct se_hba *hba = su_dev->se_dev_hba; +	struct se_device *dev = p; +	struct se_hba *hba = dev->se_hba;  	struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL;  	struct t10_alua_lu_gp_member *lu_gp_mem;  	unsigned char buf[LU_GROUP_NAME_BUF];  	int move = 0; -	dev = su_dev->se_dev_ptr; -	if (!dev) -		return -ENODEV; +	lu_gp_mem = dev->dev_alua_lu_gp_mem; +	if (!lu_gp_mem) +		return 0; -	if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) { -		pr_warn("SPC3_ALUA_EMULATED not enabled for %s/%s\n", -			config_item_name(&hba->hba_group.cg_item), -			config_item_name(&su_dev->se_dev_group.cg_item)); -		return -EINVAL; -	}  	if (count > LU_GROUP_NAME_BUF) {  		pr_err("ALUA LU Group Alias too large!\n");  		return -EINVAL; @@ -1881,14 +1670,6 @@ static ssize_t target_core_store_alua_lu_gp(  		if (!lu_gp_new)  			return -ENODEV;  	} -	lu_gp_mem = dev->dev_alua_lu_gp_mem; -	if (!lu_gp_mem) { -		if (lu_gp_new) -			core_alua_put_lu_gp_from_name(lu_gp_new); -		pr_err("NULL struct se_device->dev_alua_lu_gp_mem" -				" pointer\n"); -		return -EINVAL; -	}  	spin_lock(&lu_gp_mem->lu_gp_mem_lock);  	lu_gp = lu_gp_mem->lu_gp; @@ -1902,7 +1683,7 @@ static ssize_t target_core_store_alua_lu_gp(  				" from ALUA LU Group: core/alua/lu_gps/%s, ID:"  				" %hu\n",  				config_item_name(&hba->hba_group.cg_item), -				config_item_name(&su_dev->se_dev_group.cg_item), +				config_item_name(&dev->dev_group.cg_item),  				config_item_name(&lu_gp->lu_gp_group.cg_item),  				lu_gp->lu_gp_id); @@ -1927,7 +1708,7 @@ static ssize_t target_core_store_alua_lu_gp(  		" core/alua/lu_gps/%s, ID: %hu\n",  		(move) ? "Moving" : "Adding",  		config_item_name(&hba->hba_group.cg_item), -		config_item_name(&su_dev->se_dev_group.cg_item), +		config_item_name(&dev->dev_group.cg_item),  		config_item_name(&lu_gp_new->lu_gp_group.cg_item),  		lu_gp_new->lu_gp_id); @@ -1955,69 +1736,44 @@ static struct configfs_attribute *lio_core_dev_attrs[] = {  static void target_core_dev_release(struct config_item *item)  { -	struct se_subsystem_dev *se_dev = container_of(to_config_group(item), -				struct se_subsystem_dev, se_dev_group); -	struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); -	struct se_subsystem_api *t = hba->transport; -	struct config_group *dev_cg = &se_dev->se_dev_group; +	struct config_group *dev_cg = to_config_group(item); +	struct se_device *dev = +		container_of(dev_cg, struct se_device, dev_group);  	kfree(dev_cg->default_groups); -	/* -	 * This pointer will set when the storage is enabled with: -	 *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` -	 */ -	if (se_dev->se_dev_ptr) { -		pr_debug("Target_Core_ConfigFS: Calling se_free_" -			"virtual_device() for se_dev_ptr: %p\n", -			se_dev->se_dev_ptr); - -		se_free_virtual_device(se_dev->se_dev_ptr, hba); -	} else { -		/* -		 * Release struct se_subsystem_dev->se_dev_su_ptr.. -		 */ -		pr_debug("Target_Core_ConfigFS: Calling t->free_" -			"device() for se_dev_su_ptr: %p\n", -			se_dev->se_dev_su_ptr); - -		t->free_device(se_dev->se_dev_su_ptr); -	} - -	pr_debug("Target_Core_ConfigFS: Deallocating se_subsystem" -			"_dev_t: %p\n", se_dev); -	kfree(se_dev); +	target_free_device(dev);  }  static ssize_t target_core_dev_show(struct config_item *item,  				     struct configfs_attribute *attr,  				     char *page)  { -	struct se_subsystem_dev *se_dev = container_of( -			to_config_group(item), struct se_subsystem_dev, -			se_dev_group); +	struct config_group *dev_cg = to_config_group(item); +	struct se_device *dev = +		container_of(dev_cg, struct se_device, dev_group);  	struct target_core_configfs_attribute *tc_attr = container_of(  			attr, struct target_core_configfs_attribute, attr);  	if (!tc_attr->show)  		return -EINVAL; -	return tc_attr->show(se_dev, page); +	return tc_attr->show(dev, page);  }  static ssize_t target_core_dev_store(struct config_item *item,  				      struct configfs_attribute *attr,  				      const char *page, size_t count)  { -	struct se_subsystem_dev *se_dev = container_of( -			to_config_group(item), struct se_subsystem_dev, -			se_dev_group); +	struct config_group *dev_cg = to_config_group(item); +	struct se_device *dev = +		container_of(dev_cg, struct se_device, dev_group);  	struct target_core_configfs_attribute *tc_attr = container_of(  			attr, struct target_core_configfs_attribute, attr);  	if (!tc_attr->store)  		return -EINVAL; -	return tc_attr->store(se_dev, page, count); +	return tc_attr->store(dev, page, count);  }  static struct configfs_item_operations target_core_dev_item_ops = { @@ -2107,7 +1863,6 @@ static ssize_t target_core_alua_lu_gp_show_attr_members(  {  	struct se_device *dev;  	struct se_hba *hba; -	struct se_subsystem_dev *su_dev;  	struct t10_alua_lu_gp_member *lu_gp_mem;  	ssize_t len = 0, cur_len;  	unsigned char buf[LU_GROUP_NAME_BUF]; @@ -2117,12 +1872,11 @@ static ssize_t target_core_alua_lu_gp_show_attr_members(  	spin_lock(&lu_gp->lu_gp_lock);  	list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {  		dev = lu_gp_mem->lu_gp_mem_dev; -		su_dev = dev->se_sub_dev; -		hba = su_dev->se_dev_hba; +		hba = dev->se_hba;  		cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n",  			config_item_name(&hba->hba_group.cg_item), -			config_item_name(&su_dev->se_dev_group.cg_item)); +			config_item_name(&dev->dev_group.cg_item));  		cur_len++; /* Extra byte for NULL terminator */  		if ((cur_len + len) > PAGE_SIZE) { @@ -2260,7 +2014,7 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(  	const char *page,  	size_t count)  { -	struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; +	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;  	unsigned long tmp;  	int new_state, ret; @@ -2284,7 +2038,7 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(  		return -EINVAL;  	} -	ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr, +	ret = core_alua_do_port_transition(tg_pt_gp, dev,  					NULL, NULL, new_state, 0);  	return (!ret) ? count : -EINVAL;  } @@ -2620,11 +2374,10 @@ static struct config_group *target_core_alua_create_tg_pt_gp(  	struct t10_alua *alua = container_of(group, struct t10_alua,  					alua_tg_pt_gps_group);  	struct t10_alua_tg_pt_gp *tg_pt_gp; -	struct se_subsystem_dev *su_dev = alua->t10_sub_dev;  	struct config_group *alua_tg_pt_gp_cg = NULL;  	struct config_item *alua_tg_pt_gp_ci = NULL; -	tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0); +	tg_pt_gp = core_alua_allocate_tg_pt_gp(alua->t10_dev, name, 0);  	if (!tg_pt_gp)  		return NULL; @@ -2721,10 +2474,10 @@ static struct config_group *target_core_make_subdev(  	const char *name)  {  	struct t10_alua_tg_pt_gp *tg_pt_gp; -	struct se_subsystem_dev *se_dev;  	struct se_subsystem_api *t;  	struct config_item *hba_ci = &group->cg_item;  	struct se_hba *hba = item_to_hba(hba_ci); +	struct se_device *dev;  	struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL;  	struct config_group *dev_stat_grp = NULL;  	int errno = -ENOMEM, ret; @@ -2737,120 +2490,80 @@ static struct config_group *target_core_make_subdev(  	 */  	t = hba->transport; -	se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); -	if (!se_dev) { -		pr_err("Unable to allocate memory for" -				" struct se_subsystem_dev\n"); -		goto unlock; -	} -	INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); -	spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); -	INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); -	INIT_LIST_HEAD(&se_dev->t10_pr.aptpl_reg_list); -	spin_lock_init(&se_dev->t10_pr.registration_lock); -	spin_lock_init(&se_dev->t10_pr.aptpl_reg_lock); -	INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); -	spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); -	spin_lock_init(&se_dev->se_dev_lock); -	se_dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; -	se_dev->t10_wwn.t10_sub_dev = se_dev; -	se_dev->t10_alua.t10_sub_dev = se_dev; -	se_dev->se_dev_attrib.da_sub_dev = se_dev; - -	se_dev->se_dev_hba = hba; -	dev_cg = &se_dev->se_dev_group; - -	dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, +	dev = target_alloc_device(hba, name); +	if (!dev) +		goto out_unlock; + +	dev_cg = &dev->dev_group; + +	dev_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,  			GFP_KERNEL);  	if (!dev_cg->default_groups) -		goto out; -	/* -	 * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr -	 * for ->allocate_virtdevice() -	 * -	 * se_dev->se_dev_ptr will be set after ->create_virtdev() -	 * has been called successfully in the next level up in the -	 * configfs tree for device object's struct config_group. -	 */ -	se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name); -	if (!se_dev->se_dev_su_ptr) { -		pr_err("Unable to locate subsystem dependent pointer" -			" from allocate_virtdevice()\n"); -		goto out; -	} +		goto out_free_device; -	config_group_init_type_name(&se_dev->se_dev_group, name, -			&target_core_dev_cit); -	config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib", +	config_group_init_type_name(dev_cg, name, &target_core_dev_cit); +	config_group_init_type_name(&dev->dev_attrib.da_group, "attrib",  			&target_core_dev_attrib_cit); -	config_group_init_type_name(&se_dev->se_dev_pr_group, "pr", +	config_group_init_type_name(&dev->dev_pr_group, "pr",  			&target_core_dev_pr_cit); -	config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn", +	config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn",  			&target_core_dev_wwn_cit); -	config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, +	config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group,  			"alua", &target_core_alua_tg_pt_gps_cit); -	config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, +	config_group_init_type_name(&dev->dev_stat_grps.stat_group,  			"statistics", &target_core_stat_cit); -	dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; -	dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; -	dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; -	dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; -	dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; +	dev_cg->default_groups[0] = &dev->dev_attrib.da_group; +	dev_cg->default_groups[1] = &dev->dev_pr_group; +	dev_cg->default_groups[2] = &dev->t10_wwn.t10_wwn_group; +	dev_cg->default_groups[3] = &dev->t10_alua.alua_tg_pt_gps_group; +	dev_cg->default_groups[4] = &dev->dev_stat_grps.stat_group;  	dev_cg->default_groups[5] = NULL;  	/*  	 * Add core/$HBA/$DEV/alua/default_tg_pt_gp  	 */ -	tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); +	tg_pt_gp = core_alua_allocate_tg_pt_gp(dev, "default_tg_pt_gp", 1);  	if (!tg_pt_gp) -		goto out; +		goto out_free_dev_cg_default_groups; +	dev->t10_alua.default_tg_pt_gp = tg_pt_gp; -	tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; -	tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group; +	tg_pt_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  				GFP_KERNEL);  	if (!tg_pt_gp_cg->default_groups) {  		pr_err("Unable to allocate tg_pt_gp_cg->"  				"default_groups\n"); -		goto out; +		goto out_free_tg_pt_gp;  	}  	config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group,  			"default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit);  	tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group;  	tg_pt_gp_cg->default_groups[1] = NULL; -	se_dev->t10_alua.default_tg_pt_gp = tg_pt_gp;  	/*  	 * Add core/$HBA/$DEV/statistics/ default groups  	 */ -	dev_stat_grp = &se_dev->dev_stat_grps.stat_group; -	dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, +	dev_stat_grp = &dev->dev_stat_grps.stat_group; +	dev_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 4,  				GFP_KERNEL);  	if (!dev_stat_grp->default_groups) {  		pr_err("Unable to allocate dev_stat_grp->default_groups\n"); -		goto out; +		goto out_free_tg_pt_gp_cg_default_groups;  	} -	target_stat_setup_dev_default_groups(se_dev); - -	pr_debug("Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" -		" %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); +	target_stat_setup_dev_default_groups(dev);  	mutex_unlock(&hba->hba_access_mutex); -	return &se_dev->se_dev_group; -out: -	if (se_dev->t10_alua.default_tg_pt_gp) { -		core_alua_free_tg_pt_gp(se_dev->t10_alua.default_tg_pt_gp); -		se_dev->t10_alua.default_tg_pt_gp = NULL; -	} -	if (dev_stat_grp) -		kfree(dev_stat_grp->default_groups); -	if (tg_pt_gp_cg) -		kfree(tg_pt_gp_cg->default_groups); -	if (dev_cg) -		kfree(dev_cg->default_groups); -	if (se_dev->se_dev_su_ptr) -		t->free_device(se_dev->se_dev_su_ptr); -	kfree(se_dev); -unlock: +	return dev_cg; + +out_free_tg_pt_gp_cg_default_groups: +	kfree(tg_pt_gp_cg->default_groups); +out_free_tg_pt_gp: +	core_alua_free_tg_pt_gp(tg_pt_gp); +out_free_dev_cg_default_groups: +	kfree(dev_cg->default_groups); +out_free_device: +	target_free_device(dev); +out_unlock:  	mutex_unlock(&hba->hba_access_mutex);  	return ERR_PTR(errno);  } @@ -2859,18 +2572,19 @@ static void target_core_drop_subdev(  	struct config_group *group,  	struct config_item *item)  { -	struct se_subsystem_dev *se_dev = container_of(to_config_group(item), -				struct se_subsystem_dev, se_dev_group); +	struct config_group *dev_cg = to_config_group(item); +	struct se_device *dev = +		container_of(dev_cg, struct se_device, dev_group);  	struct se_hba *hba;  	struct config_item *df_item; -	struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; +	struct config_group *tg_pt_gp_cg, *dev_stat_grp;  	int i; -	hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); +	hba = item_to_hba(&dev->se_hba->hba_group.cg_item);  	mutex_lock(&hba->hba_access_mutex); -	dev_stat_grp = &se_dev->dev_stat_grps.stat_group; +	dev_stat_grp = &dev->dev_stat_grps.stat_group;  	for (i = 0; dev_stat_grp->default_groups[i]; i++) {  		df_item = &dev_stat_grp->default_groups[i]->cg_item;  		dev_stat_grp->default_groups[i] = NULL; @@ -2878,7 +2592,7 @@ static void target_core_drop_subdev(  	}  	kfree(dev_stat_grp->default_groups); -	tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; +	tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;  	for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) {  		df_item = &tg_pt_gp_cg->default_groups[i]->cg_item;  		tg_pt_gp_cg->default_groups[i] = NULL; @@ -2889,17 +2603,15 @@ static void target_core_drop_subdev(  	 * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp  	 * directly from target_core_alua_tg_pt_gp_release().  	 */ -	se_dev->t10_alua.default_tg_pt_gp = NULL; +	dev->t10_alua.default_tg_pt_gp = NULL; -	dev_cg = &se_dev->se_dev_group;  	for (i = 0; dev_cg->default_groups[i]; i++) {  		df_item = &dev_cg->default_groups[i]->cg_item;  		dev_cg->default_groups[i] = NULL;  		config_item_put(df_item);  	}  	/* -	 * The releasing of se_dev and associated se_dev->se_dev_ptr is done -	 * from target_core_dev_item_ops->release() ->target_core_dev_release(). +	 * se_dev is released from target_core_dev_item_ops->release()  	 */  	config_item_put(item);  	mutex_unlock(&hba->hba_access_mutex); @@ -2962,13 +2674,10 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba,  		return -EINVAL;  	} -	spin_lock(&hba->device_lock); -	if (!list_empty(&hba->hba_dev_list)) { +	if (hba->dev_count) {  		pr_err("Unable to set hba_mode with active devices\n"); -		spin_unlock(&hba->device_lock);  		return -EINVAL;  	} -	spin_unlock(&hba->device_lock);  	ret = transport->pmode_enable_hba(hba, mode_flag);  	if (ret < 0) @@ -3120,7 +2829,7 @@ static int __init target_core_init_configfs(void)  	 * and ALUA Logical Unit Group and Target Port Group infrastructure.  	 */  	target_cg = &subsys->su_group; -	target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	target_cg->default_groups = kmalloc(sizeof(struct config_group) * 2,  				GFP_KERNEL);  	if (!target_cg->default_groups) {  		pr_err("Unable to allocate target_cg->default_groups\n"); @@ -3136,7 +2845,7 @@ static int __init target_core_init_configfs(void)  	 * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/  	 */  	hba_cg = &target_core_hbagroup; -	hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	hba_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  				GFP_KERNEL);  	if (!hba_cg->default_groups) {  		pr_err("Unable to allocate hba_cg->default_groups\n"); @@ -3152,7 +2861,7 @@ static int __init target_core_init_configfs(void)  	 * groups under /sys/kernel/config/target/core/alua/  	 */  	alua_cg = &alua_group; -	alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	alua_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  			GFP_KERNEL);  	if (!alua_cg->default_groups) {  		pr_err("Unable to allocate alua_cg->default_groups\n"); @@ -3174,7 +2883,7 @@ static int __init target_core_init_configfs(void)  	}  	lu_gp_cg = &alua_lu_gps_group; -	lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	lu_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  			GFP_KERNEL);  	if (!lu_gp_cg->default_groups) {  		pr_err("Unable to allocate lu_gp_cg->default_groups\n"); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9abef9f8eb76..e2695101bb99 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -4,10 +4,7 @@   * This file contains the TCM Virtual Device and Disk Transport   * agnostic related functions.   * - * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005-2006 SBE, Inc.  All Rights Reserved. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2003-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -50,26 +47,20 @@  #include "target_core_pr.h"  #include "target_core_ua.h" -static void se_dev_start(struct se_device *dev); -static void se_dev_stop(struct se_device *dev); -  static struct se_hba *lun0_hba; -static struct se_subsystem_dev *lun0_su_dev;  /* not static, needed by tpg.c */  struct se_device *g_lun0_dev; -int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) +sense_reason_t +transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  {  	struct se_lun *se_lun = NULL;  	struct se_session *se_sess = se_cmd->se_sess;  	struct se_device *dev;  	unsigned long flags; -	if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { -		se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; -		se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		return -ENODEV; -	} +	if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) +		return TCM_NON_EXISTENT_LUN;  	spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags);  	se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; @@ -81,14 +72,12 @@ int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  		if ((se_cmd->data_direction == DMA_TO_DEVICE) &&  		    (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { -			se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; -			se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  			pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN"  				" Access for 0x%08x\n",  				se_cmd->se_tfo->get_fabric_name(),  				unpacked_lun);  			spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); -			return -EACCES; +			return TCM_WRITE_PROTECTED;  		}  		if (se_cmd->data_direction == DMA_TO_DEVICE) @@ -113,38 +102,24 @@ int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  		 * MappedLUN=0 exists for this Initiator Port.  		 */  		if (unpacked_lun != 0) { -			se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; -			se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  			pr_err("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN"  				" Access for 0x%08x\n",  				se_cmd->se_tfo->get_fabric_name(),  				unpacked_lun); -			return -ENODEV; +			return TCM_NON_EXISTENT_LUN;  		}  		/*  		 * Force WRITE PROTECT for virtual LUN 0  		 */  		if ((se_cmd->data_direction != DMA_FROM_DEVICE) && -		    (se_cmd->data_direction != DMA_NONE)) { -			se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; -			se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -			return -EACCES; -		} +		    (se_cmd->data_direction != DMA_NONE)) +			return TCM_WRITE_PROTECTED;  		se_lun = &se_sess->se_tpg->tpg_virt_lun0;  		se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0;  		se_cmd->orig_fe_lun = 0;  		se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;  	} -	/* -	 * Determine if the struct se_lun is online. -	 * FIXME: Check for LUN_RESET + UNIT Attention -	 */ -	if (se_dev_check_online(se_lun->lun_se_dev) != 0) { -		se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; -		se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		return -ENODEV; -	}  	/* Directly associate cmd with se_dev */  	se_cmd->se_dev = se_lun->lun_se_dev; @@ -175,11 +150,8 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  	struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;  	unsigned long flags; -	if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { -		se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; -		se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; +	if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG)  		return -ENODEV; -	}  	spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags);  	se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; @@ -199,15 +171,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  			" Access for 0x%08x\n",  			se_cmd->se_tfo->get_fabric_name(),  			unpacked_lun); -		se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		return -ENODEV; -	} -	/* -	 * Determine if the struct se_lun is online. -	 * FIXME: Check for LUN_RESET + UNIT Attention -	 */ -	if (se_dev_check_online(se_lun->lun_se_dev) != 0) { -		se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;  		return -ENODEV;  	} @@ -565,7 +528,6 @@ static void core_export_port(  	struct se_port *port,  	struct se_lun *lun)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL;  	spin_lock(&dev->se_port_lock); @@ -578,7 +540,8 @@ static void core_export_port(  	list_add_tail(&port->sep_list, &dev->dev_sep_list);  	spin_unlock(&dev->se_port_lock); -	if (su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { +	if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV && +	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {  		tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port);  		if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) {  			pr_err("Unable to allocate t10_alua_tg_pt" @@ -587,7 +550,7 @@ static void core_export_port(  		}  		spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);  		__core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, -			su_dev->t10_alua.default_tg_pt_gp); +			dev->t10_alua.default_tg_pt_gp);  		spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);  		pr_debug("%s/%s: Adding to default ALUA Target Port"  			" Group: alua/default_tg_pt_gp\n", @@ -625,6 +588,7 @@ int core_dev_export(  	struct se_portal_group *tpg,  	struct se_lun *lun)  { +	struct se_hba *hba = dev->se_hba;  	struct se_port *port;  	port = core_alloc_port(dev); @@ -632,9 +596,11 @@ int core_dev_export(  		return PTR_ERR(port);  	lun->lun_se_dev = dev; -	se_dev_start(dev); -	atomic_inc(&dev->dev_export_obj.obj_access_count); +	spin_lock(&hba->device_lock); +	dev->export_count++; +	spin_unlock(&hba->device_lock); +  	core_export_port(dev, tpg, port, lun);  	return 0;  } @@ -644,6 +610,7 @@ void core_dev_unexport(  	struct se_portal_group *tpg,  	struct se_lun *lun)  { +	struct se_hba *hba = dev->se_hba;  	struct se_port *port = lun->lun_sep;  	spin_lock(&lun->lun_sep_lock); @@ -654,198 +621,27 @@ void core_dev_unexport(  	spin_unlock(&lun->lun_sep_lock);  	spin_lock(&dev->se_port_lock); -	atomic_dec(&dev->dev_export_obj.obj_access_count);  	core_release_port(dev, port);  	spin_unlock(&dev->se_port_lock); -	se_dev_stop(dev); -	lun->lun_se_dev = NULL; -} - -int target_report_luns(struct se_cmd *se_cmd) -{ -	struct se_dev_entry *deve; -	struct se_session *se_sess = se_cmd->se_sess; -	unsigned char *buf; -	u32 lun_count = 0, offset = 8, i; - -	if (se_cmd->data_length < 16) { -		pr_warn("REPORT LUNS allocation length %u too small\n", -			se_cmd->data_length); -		se_cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; -	} - -	buf = transport_kmap_data_sg(se_cmd); -	if (!buf) -		return -ENOMEM; - -	/* -	 * If no struct se_session pointer is present, this struct se_cmd is -	 * coming via a target_core_mod PASSTHROUGH op, and not through -	 * a $FABRIC_MOD.  In that case, report LUN=0 only. -	 */ -	if (!se_sess) { -		int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); -		lun_count = 1; -		goto done; -	} - -	spin_lock_irq(&se_sess->se_node_acl->device_list_lock); -	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { -		deve = se_sess->se_node_acl->device_list[i]; -		if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) -			continue; -		/* -		 * We determine the correct LUN LIST LENGTH even once we -		 * have reached the initial allocation length. -		 * See SPC2-R20 7.19. -		 */ -		lun_count++; -		if ((offset + 8) > se_cmd->data_length) -			continue; - -		int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); -		offset += 8; -	} -	spin_unlock_irq(&se_sess->se_node_acl->device_list_lock); - -	/* -	 * See SPC3 r07, page 159. -	 */ -done: -	lun_count *= 8; -	buf[0] = ((lun_count >> 24) & 0xff); -	buf[1] = ((lun_count >> 16) & 0xff); -	buf[2] = ((lun_count >> 8) & 0xff); -	buf[3] = (lun_count & 0xff); -	transport_kunmap_data_sg(se_cmd); - -	target_complete_cmd(se_cmd, GOOD); -	return 0; -} - -/*	se_release_device_for_hba(): - * - * - */ -void se_release_device_for_hba(struct se_device *dev) -{ -	struct se_hba *hba = dev->se_hba; - -	if ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) || -	    (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) || -	    (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) || -	    (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_ACTIVATED) || -	    (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_DEACTIVATED)) -		se_dev_stop(dev); - -	if (dev->dev_ptr) { -		destroy_workqueue(dev->tmr_wq); -		if (dev->transport->free_device) -			dev->transport->free_device(dev->dev_ptr); -	} -  	spin_lock(&hba->device_lock); -	list_del(&dev->dev_list); -	hba->dev_count--; +	dev->export_count--;  	spin_unlock(&hba->device_lock); -	core_scsi3_free_all_registrations(dev); -	se_release_vpd_for_dev(dev); - -	kfree(dev); +	lun->lun_se_dev = NULL;  } -void se_release_vpd_for_dev(struct se_device *dev) +static void se_release_vpd_for_dev(struct se_device *dev)  {  	struct t10_vpd *vpd, *vpd_tmp; -	spin_lock(&dev->se_sub_dev->t10_wwn.t10_vpd_lock); +	spin_lock(&dev->t10_wwn.t10_vpd_lock);  	list_for_each_entry_safe(vpd, vpd_tmp, -			&dev->se_sub_dev->t10_wwn.t10_vpd_list, vpd_list) { +			&dev->t10_wwn.t10_vpd_list, vpd_list) {  		list_del(&vpd->vpd_list);  		kfree(vpd);  	} -	spin_unlock(&dev->se_sub_dev->t10_wwn.t10_vpd_lock); -} - -/*	se_free_virtual_device(): - * - *	Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. - */ -int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) -{ -	if (!list_empty(&dev->dev_sep_list)) -		dump_stack(); - -	core_alua_free_lu_gp_mem(dev); -	se_release_device_for_hba(dev); - -	return 0; -} - -static void se_dev_start(struct se_device *dev) -{ -	struct se_hba *hba = dev->se_hba; - -	spin_lock(&hba->device_lock); -	atomic_inc(&dev->dev_obj.obj_access_count); -	if (atomic_read(&dev->dev_obj.obj_access_count) == 1) { -		if (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) { -			dev->dev_status &= ~TRANSPORT_DEVICE_DEACTIVATED; -			dev->dev_status |= TRANSPORT_DEVICE_ACTIVATED; -		} else if (dev->dev_status & -			   TRANSPORT_DEVICE_OFFLINE_DEACTIVATED) { -			dev->dev_status &= -				~TRANSPORT_DEVICE_OFFLINE_DEACTIVATED; -			dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_ACTIVATED; -		} -	} -	spin_unlock(&hba->device_lock); -} - -static void se_dev_stop(struct se_device *dev) -{ -	struct se_hba *hba = dev->se_hba; - -	spin_lock(&hba->device_lock); -	atomic_dec(&dev->dev_obj.obj_access_count); -	if (atomic_read(&dev->dev_obj.obj_access_count) == 0) { -		if (dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) { -			dev->dev_status &= ~TRANSPORT_DEVICE_ACTIVATED; -			dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; -		} else if (dev->dev_status & -			   TRANSPORT_DEVICE_OFFLINE_ACTIVATED) { -			dev->dev_status &= ~TRANSPORT_DEVICE_OFFLINE_ACTIVATED; -			dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_DEACTIVATED; -		} -	} -	spin_unlock(&hba->device_lock); -} - -int se_dev_check_online(struct se_device *dev) -{ -	unsigned long flags; -	int ret; - -	spin_lock_irqsave(&dev->dev_status_lock, flags); -	ret = ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) || -	       (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED)) ? 0 : 1; -	spin_unlock_irqrestore(&dev->dev_status_lock, flags); - -	return ret; -} - -int se_dev_check_shutdown(struct se_device *dev) -{ -	int ret; - -	spin_lock_irq(&dev->dev_status_lock); -	ret = (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN); -	spin_unlock_irq(&dev->dev_status_lock); - -	return ret; +	spin_unlock(&dev->t10_wwn.t10_vpd_lock);  }  static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) @@ -866,72 +662,13 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)  	return aligned_max_sectors;  } -void se_dev_set_default_attribs( -	struct se_device *dev, -	struct se_dev_limits *dev_limits) -{ -	struct queue_limits *limits = &dev_limits->limits; - -	dev->se_sub_dev->se_dev_attrib.emulate_dpo = DA_EMULATE_DPO; -	dev->se_sub_dev->se_dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; -	dev->se_sub_dev->se_dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; -	dev->se_sub_dev->se_dev_attrib.emulate_write_cache = DA_EMULATE_WRITE_CACHE; -	dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; -	dev->se_sub_dev->se_dev_attrib.emulate_tas = DA_EMULATE_TAS; -	dev->se_sub_dev->se_dev_attrib.emulate_tpu = DA_EMULATE_TPU; -	dev->se_sub_dev->se_dev_attrib.emulate_tpws = DA_EMULATE_TPWS; -	dev->se_sub_dev->se_dev_attrib.emulate_reservations = DA_EMULATE_RESERVATIONS; -	dev->se_sub_dev->se_dev_attrib.emulate_alua = DA_EMULATE_ALUA; -	dev->se_sub_dev->se_dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; -	dev->se_sub_dev->se_dev_attrib.is_nonrot = DA_IS_NONROT; -	dev->se_sub_dev->se_dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; -	/* -	 * The TPU=1 and TPWS=1 settings will be set in TCM/IBLOCK -	 * iblock_create_virtdevice() from struct queue_limits values -	 * if blk_queue_discard()==1 -	 */ -	dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT; -	dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = -		DA_MAX_UNMAP_BLOCK_DESC_COUNT; -	dev->se_sub_dev->se_dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT; -	dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = -				DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; -	/* -	 * block_size is based on subsystem plugin dependent requirements. -	 */ -	dev->se_sub_dev->se_dev_attrib.hw_block_size = limits->logical_block_size; -	dev->se_sub_dev->se_dev_attrib.block_size = limits->logical_block_size; -	/* -	 * Align max_hw_sectors down to PAGE_SIZE I/O transfers -	 */ -	limits->max_hw_sectors = se_dev_align_max_sectors(limits->max_hw_sectors, -						limits->logical_block_size); -	dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors; - -	/* -	 * Set fabric_max_sectors, which is reported in block limits -	 * VPD page (B0h). -	 */ -	dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS; -	/* -	 * Set optimal_sectors from fabric_max_sectors, which can be -	 * lowered via configfs. -	 */ -	dev->se_sub_dev->se_dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; -	/* -	 * queue_depth is based on subsystem plugin dependent requirements. -	 */ -	dev->se_sub_dev->se_dev_attrib.hw_queue_depth = dev_limits->hw_queue_depth; -	dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth; -} -  int se_dev_set_max_unmap_lba_count(  	struct se_device *dev,  	u32 max_unmap_lba_count)  { -	dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count = max_unmap_lba_count; +	dev->dev_attrib.max_unmap_lba_count = max_unmap_lba_count;  	pr_debug("dev[%p]: Set max_unmap_lba_count: %u\n", -			dev, dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count); +			dev, dev->dev_attrib.max_unmap_lba_count);  	return 0;  } @@ -939,10 +676,10 @@ int se_dev_set_max_unmap_block_desc_count(  	struct se_device *dev,  	u32 max_unmap_block_desc_count)  { -	dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = +	dev->dev_attrib.max_unmap_block_desc_count =  		max_unmap_block_desc_count;  	pr_debug("dev[%p]: Set max_unmap_block_desc_count: %u\n", -			dev, dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count); +			dev, dev->dev_attrib.max_unmap_block_desc_count);  	return 0;  } @@ -950,9 +687,9 @@ int se_dev_set_unmap_granularity(  	struct se_device *dev,  	u32 unmap_granularity)  { -	dev->se_sub_dev->se_dev_attrib.unmap_granularity = unmap_granularity; +	dev->dev_attrib.unmap_granularity = unmap_granularity;  	pr_debug("dev[%p]: Set unmap_granularity: %u\n", -			dev, dev->se_sub_dev->se_dev_attrib.unmap_granularity); +			dev, dev->dev_attrib.unmap_granularity);  	return 0;  } @@ -960,9 +697,19 @@ int se_dev_set_unmap_granularity_alignment(  	struct se_device *dev,  	u32 unmap_granularity_alignment)  { -	dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = unmap_granularity_alignment; +	dev->dev_attrib.unmap_granularity_alignment = unmap_granularity_alignment;  	pr_debug("dev[%p]: Set unmap_granularity_alignment: %u\n", -			dev, dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment); +			dev, dev->dev_attrib.unmap_granularity_alignment); +	return 0; +} + +int se_dev_set_max_write_same_len( +	struct se_device *dev, +	u32 max_write_same_len) +{ +	dev->dev_attrib.max_write_same_len = max_write_same_len; +	pr_debug("dev[%p]: Set max_write_same_len: %u\n", +			dev, dev->dev_attrib.max_write_same_len);  	return 0;  } @@ -993,9 +740,9 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)  		pr_err("emulate_fua_write not supported for pSCSI\n");  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag; +	dev->dev_attrib.emulate_fua_write = flag;  	pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n", -			dev, dev->se_sub_dev->se_dev_attrib.emulate_fua_write); +			dev, dev->dev_attrib.emulate_fua_write);  	return 0;  } @@ -1025,9 +772,9 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)  		pr_err("emulate_write_cache not supported for pSCSI\n");  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag; +	dev->dev_attrib.emulate_write_cache = flag;  	pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", -			dev, dev->se_sub_dev->se_dev_attrib.emulate_write_cache); +			dev, dev->dev_attrib.emulate_write_cache);  	return 0;  } @@ -1038,16 +785,15 @@ int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag)  		return -EINVAL;  	} -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_err("dev[%p]: Unable to change SE Device" -			" UA_INTRLCK_CTRL while dev_export_obj: %d count" -			" exists\n", dev, -			atomic_read(&dev->dev_export_obj.obj_access_count)); +			" UA_INTRLCK_CTRL while export_count is %d\n", +			dev, dev->export_count);  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl = flag; +	dev->dev_attrib.emulate_ua_intlck_ctrl = flag;  	pr_debug("dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", -		dev, dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl); +		dev, dev->dev_attrib.emulate_ua_intlck_ctrl);  	return 0;  } @@ -1059,15 +805,15 @@ int se_dev_set_emulate_tas(struct se_device *dev, int flag)  		return -EINVAL;  	} -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_err("dev[%p]: Unable to change SE Device TAS while" -			" dev_export_obj: %d count exists\n", dev, -			atomic_read(&dev->dev_export_obj.obj_access_count)); +			" export_count is %d\n", +			dev, dev->export_count);  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_tas = flag; +	dev->dev_attrib.emulate_tas = flag;  	pr_debug("dev[%p]: SE Device TASK_ABORTED status bit: %s\n", -		dev, (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? "Enabled" : "Disabled"); +		dev, (dev->dev_attrib.emulate_tas) ? "Enabled" : "Disabled");  	return 0;  } @@ -1082,12 +828,12 @@ int se_dev_set_emulate_tpu(struct se_device *dev, int flag)  	 * We expect this value to be non-zero when generic Block Layer  	 * Discard supported is detected iblock_create_virtdevice().  	 */ -	if (flag && !dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { +	if (flag && !dev->dev_attrib.max_unmap_block_desc_count) {  		pr_err("Generic Block Discard not supported\n");  		return -ENOSYS;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_tpu = flag; +	dev->dev_attrib.emulate_tpu = flag;  	pr_debug("dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n",  				dev, flag);  	return 0; @@ -1103,12 +849,12 @@ int se_dev_set_emulate_tpws(struct se_device *dev, int flag)  	 * We expect this value to be non-zero when generic Block Layer  	 * Discard supported is detected iblock_create_virtdevice().  	 */ -	if (flag && !dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { +	if (flag && !dev->dev_attrib.max_unmap_block_desc_count) {  		pr_err("Generic Block Discard not supported\n");  		return -ENOSYS;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_tpws = flag; +	dev->dev_attrib.emulate_tpws = flag;  	pr_debug("dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n",  				dev, flag);  	return 0; @@ -1120,9 +866,9 @@ int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)  		pr_err("Illegal value %d\n", flag);  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.enforce_pr_isids = flag; +	dev->dev_attrib.enforce_pr_isids = flag;  	pr_debug("dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev, -		(dev->se_sub_dev->se_dev_attrib.enforce_pr_isids) ? "Enabled" : "Disabled"); +		(dev->dev_attrib.enforce_pr_isids) ? "Enabled" : "Disabled");  	return 0;  } @@ -1132,7 +878,7 @@ int se_dev_set_is_nonrot(struct se_device *dev, int flag)  		printk(KERN_ERR "Illegal value %d\n", flag);  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.is_nonrot = flag; +	dev->dev_attrib.is_nonrot = flag;  	pr_debug("dev[%p]: SE Device is_nonrot bit: %d\n",  	       dev, flag);  	return 0; @@ -1145,7 +891,7 @@ int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag)  			" reordering not implemented\n", dev);  		return -ENOSYS;  	} -	dev->se_sub_dev->se_dev_attrib.emulate_rest_reord = flag; +	dev->dev_attrib.emulate_rest_reord = flag;  	pr_debug("dev[%p]: SE Device emulate_rest_reord: %d\n", dev, flag);  	return 0;  } @@ -1155,10 +901,10 @@ int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag)   */  int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)  { -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_err("dev[%p]: Unable to change SE Device TCQ while" -			" dev_export_obj: %d count exists\n", dev, -			atomic_read(&dev->dev_export_obj.obj_access_count)); +			" export_count is %d\n", +			dev, dev->export_count);  		return -EINVAL;  	}  	if (!queue_depth) { @@ -1168,26 +914,26 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)  	}  	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { -		if (queue_depth > dev->se_sub_dev->se_dev_attrib.hw_queue_depth) { +		if (queue_depth > dev->dev_attrib.hw_queue_depth) {  			pr_err("dev[%p]: Passed queue_depth: %u"  				" exceeds TCM/SE_Device TCQ: %u\n",  				dev, queue_depth, -				dev->se_sub_dev->se_dev_attrib.hw_queue_depth); +				dev->dev_attrib.hw_queue_depth);  			return -EINVAL;  		}  	} else { -		if (queue_depth > dev->se_sub_dev->se_dev_attrib.queue_depth) { -			if (queue_depth > dev->se_sub_dev->se_dev_attrib.hw_queue_depth) { +		if (queue_depth > dev->dev_attrib.queue_depth) { +			if (queue_depth > dev->dev_attrib.hw_queue_depth) {  				pr_err("dev[%p]: Passed queue_depth:"  					" %u exceeds TCM/SE_Device MAX"  					" TCQ: %u\n", dev, queue_depth, -					dev->se_sub_dev->se_dev_attrib.hw_queue_depth); +					dev->dev_attrib.hw_queue_depth);  				return -EINVAL;  			}  		}  	} -	dev->se_sub_dev->se_dev_attrib.queue_depth = dev->queue_depth = queue_depth; +	dev->dev_attrib.queue_depth = dev->queue_depth = queue_depth;  	pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n",  			dev, queue_depth);  	return 0; @@ -1195,10 +941,10 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)  int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)  { -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_err("dev[%p]: Unable to change SE Device" -			" fabric_max_sectors while dev_export_obj: %d count exists\n", -			dev, atomic_read(&dev->dev_export_obj.obj_access_count)); +			" fabric_max_sectors while export_count is %d\n", +			dev, dev->export_count);  		return -EINVAL;  	}  	if (!fabric_max_sectors) { @@ -1213,11 +959,11 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)  		return -EINVAL;  	}  	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { -		if (fabric_max_sectors > dev->se_sub_dev->se_dev_attrib.hw_max_sectors) { +		if (fabric_max_sectors > dev->dev_attrib.hw_max_sectors) {  			pr_err("dev[%p]: Passed fabric_max_sectors: %u"  				" greater than TCM/SE_Device max_sectors:"  				" %u\n", dev, fabric_max_sectors, -				dev->se_sub_dev->se_dev_attrib.hw_max_sectors); +				dev->dev_attrib.hw_max_sectors);  			 return -EINVAL;  		}  	} else { @@ -1233,9 +979,9 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)  	 * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()  	 */  	fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors, -						      dev->se_sub_dev->se_dev_attrib.block_size); +						      dev->dev_attrib.block_size); -	dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = fabric_max_sectors; +	dev->dev_attrib.fabric_max_sectors = fabric_max_sectors;  	pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",  			dev, fabric_max_sectors);  	return 0; @@ -1243,10 +989,10 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)  int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)  { -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_err("dev[%p]: Unable to change SE Device" -			" optimal_sectors while dev_export_obj: %d count exists\n", -			dev, atomic_read(&dev->dev_export_obj.obj_access_count)); +			" optimal_sectors while export_count is %d\n", +			dev, dev->export_count);  		return -EINVAL;  	}  	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { @@ -1254,14 +1000,14 @@ int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)  				" changed for TCM/pSCSI\n", dev);  		return -EINVAL;  	} -	if (optimal_sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) { +	if (optimal_sectors > dev->dev_attrib.fabric_max_sectors) {  		pr_err("dev[%p]: Passed optimal_sectors %u cannot be"  			" greater than fabric_max_sectors: %u\n", dev, -			optimal_sectors, dev->se_sub_dev->se_dev_attrib.fabric_max_sectors); +			optimal_sectors, dev->dev_attrib.fabric_max_sectors);  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.optimal_sectors = optimal_sectors; +	dev->dev_attrib.optimal_sectors = optimal_sectors;  	pr_debug("dev[%p]: SE Device optimal_sectors changed to %u\n",  			dev, optimal_sectors);  	return 0; @@ -1269,10 +1015,10 @@ int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)  int se_dev_set_block_size(struct se_device *dev, u32 block_size)  { -	if (atomic_read(&dev->dev_export_obj.obj_access_count)) { +	if (dev->export_count) {  		pr_err("dev[%p]: Unable to change SE Device block_size" -			" while dev_export_obj: %d count exists\n", dev, -			atomic_read(&dev->dev_export_obj.obj_access_count)); +			" while export_count is %d\n", +			dev, dev->export_count);  		return -EINVAL;  	} @@ -1293,7 +1039,7 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size)  		return -EINVAL;  	} -	dev->se_sub_dev->se_dev_attrib.block_size = block_size; +	dev->dev_attrib.block_size = block_size;  	pr_debug("dev[%p]: SE Device block_size changed to %u\n",  			dev, block_size);  	return 0; @@ -1307,12 +1053,6 @@ struct se_lun *core_dev_add_lun(  	struct se_lun *lun_p;  	int rc; -	if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) { -		pr_err("Unable to export struct se_device while dev_access_obj: %d\n", -			atomic_read(&dev->dev_access_obj.obj_access_count)); -		return ERR_PTR(-EACCES); -	} -  	lun_p = core_tpg_pre_addlun(tpg, lun);  	if (IS_ERR(lun_p))  		return lun_p; @@ -1568,12 +1308,211 @@ void core_dev_free_initiator_node_lun_acl(  	kfree(lacl);  } +static void scsi_dump_inquiry(struct se_device *dev) +{ +	struct t10_wwn *wwn = &dev->t10_wwn; +	char buf[17]; +	int i, device_type; +	/* +	 * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer +	 */ +	for (i = 0; i < 8; i++) +		if (wwn->vendor[i] >= 0x20) +			buf[i] = wwn->vendor[i]; +		else +			buf[i] = ' '; +	buf[i] = '\0'; +	pr_debug("  Vendor: %s\n", buf); + +	for (i = 0; i < 16; i++) +		if (wwn->model[i] >= 0x20) +			buf[i] = wwn->model[i]; +		else +			buf[i] = ' '; +	buf[i] = '\0'; +	pr_debug("  Model: %s\n", buf); + +	for (i = 0; i < 4; i++) +		if (wwn->revision[i] >= 0x20) +			buf[i] = wwn->revision[i]; +		else +			buf[i] = ' '; +	buf[i] = '\0'; +	pr_debug("  Revision: %s\n", buf); + +	device_type = dev->transport->get_device_type(dev); +	pr_debug("  Type:   %s ", scsi_device_type(device_type)); +} + +struct se_device *target_alloc_device(struct se_hba *hba, const char *name) +{ +	struct se_device *dev; + +	dev = hba->transport->alloc_device(hba, name); +	if (!dev) +		return NULL; + +	dev->dev_link_magic = SE_DEV_LINK_MAGIC; +	dev->se_hba = hba; +	dev->transport = hba->transport; + +	INIT_LIST_HEAD(&dev->dev_list); +	INIT_LIST_HEAD(&dev->dev_sep_list); +	INIT_LIST_HEAD(&dev->dev_tmr_list); +	INIT_LIST_HEAD(&dev->delayed_cmd_list); +	INIT_LIST_HEAD(&dev->state_list); +	INIT_LIST_HEAD(&dev->qf_cmd_list); +	spin_lock_init(&dev->stats_lock); +	spin_lock_init(&dev->execute_task_lock); +	spin_lock_init(&dev->delayed_cmd_lock); +	spin_lock_init(&dev->dev_reservation_lock); +	spin_lock_init(&dev->se_port_lock); +	spin_lock_init(&dev->se_tmr_lock); +	spin_lock_init(&dev->qf_cmd_lock); +	atomic_set(&dev->dev_ordered_id, 0); +	INIT_LIST_HEAD(&dev->t10_wwn.t10_vpd_list); +	spin_lock_init(&dev->t10_wwn.t10_vpd_lock); +	INIT_LIST_HEAD(&dev->t10_pr.registration_list); +	INIT_LIST_HEAD(&dev->t10_pr.aptpl_reg_list); +	spin_lock_init(&dev->t10_pr.registration_lock); +	spin_lock_init(&dev->t10_pr.aptpl_reg_lock); +	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; + +	dev->dev_attrib.da_dev = dev; +	dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO; +	dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; +	dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; +	dev->dev_attrib.emulate_write_cache = DA_EMULATE_WRITE_CACHE; +	dev->dev_attrib.emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; +	dev->dev_attrib.emulate_tas = DA_EMULATE_TAS; +	dev->dev_attrib.emulate_tpu = DA_EMULATE_TPU; +	dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS; +	dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; +	dev->dev_attrib.is_nonrot = DA_IS_NONROT; +	dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; +	dev->dev_attrib.max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT; +	dev->dev_attrib.max_unmap_block_desc_count = +		DA_MAX_UNMAP_BLOCK_DESC_COUNT; +	dev->dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT; +	dev->dev_attrib.unmap_granularity_alignment = +				DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; +	dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN; +	dev->dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS; +	dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; + +	return dev; +} + +int target_configure_device(struct se_device *dev) +{ +	struct se_hba *hba = dev->se_hba; +	int ret; + +	if (dev->dev_flags & DF_CONFIGURED) { +		pr_err("se_dev->se_dev_ptr already set for storage" +				" object\n"); +		return -EEXIST; +	} + +	ret = dev->transport->configure_device(dev); +	if (ret) +		goto out; +	dev->dev_flags |= DF_CONFIGURED; + +	/* +	 * XXX: there is not much point to have two different values here.. +	 */ +	dev->dev_attrib.block_size = dev->dev_attrib.hw_block_size; +	dev->dev_attrib.queue_depth = dev->dev_attrib.hw_queue_depth; + +	/* +	 * Align max_hw_sectors down to PAGE_SIZE I/O transfers +	 */ +	dev->dev_attrib.hw_max_sectors = +		se_dev_align_max_sectors(dev->dev_attrib.hw_max_sectors, +					 dev->dev_attrib.hw_block_size); + +	dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); +	dev->creation_time = get_jiffies_64(); + +	ret = core_setup_alua(dev); +	if (ret) +		goto out; + +	/* +	 * Startup the struct se_device processing thread +	 */ +	dev->tmr_wq = alloc_workqueue("tmr-%s", WQ_MEM_RECLAIM | WQ_UNBOUND, 1, +				      dev->transport->name); +	if (!dev->tmr_wq) { +		pr_err("Unable to create tmr workqueue for %s\n", +			dev->transport->name); +		ret = -ENOMEM; +		goto out_free_alua; +	} + +	/* +	 * Setup work_queue for QUEUE_FULL +	 */ +	INIT_WORK(&dev->qf_work_queue, target_qf_do_work); + +	/* +	 * Preload the initial INQUIRY const values if we are doing +	 * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI +	 * passthrough because this is being provided by the backend LLD. +	 */ +	if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { +		strncpy(&dev->t10_wwn.vendor[0], "LIO-ORG", 8); +		strncpy(&dev->t10_wwn.model[0], +			dev->transport->inquiry_prod, 16); +		strncpy(&dev->t10_wwn.revision[0], +			dev->transport->inquiry_rev, 4); +	} + +	scsi_dump_inquiry(dev); + +	spin_lock(&hba->device_lock); +	hba->dev_count++; +	spin_unlock(&hba->device_lock); +	return 0; + +out_free_alua: +	core_alua_free_lu_gp_mem(dev); +out: +	se_release_vpd_for_dev(dev); +	return ret; +} + +void target_free_device(struct se_device *dev) +{ +	struct se_hba *hba = dev->se_hba; + +	WARN_ON(!list_empty(&dev->dev_sep_list)); + +	if (dev->dev_flags & DF_CONFIGURED) { +		destroy_workqueue(dev->tmr_wq); + +		spin_lock(&hba->device_lock); +		hba->dev_count--; +		spin_unlock(&hba->device_lock); +	} + +	core_alua_free_lu_gp_mem(dev); +	core_scsi3_free_all_registrations(dev); +	se_release_vpd_for_dev(dev); + +	dev->transport->free_device(dev); +} +  int core_dev_setup_virtual_lun0(void)  {  	struct se_hba *hba;  	struct se_device *dev; -	struct se_subsystem_dev *se_dev = NULL; -	struct se_subsystem_api *t;  	char buf[16];  	int ret; @@ -1581,60 +1520,28 @@ int core_dev_setup_virtual_lun0(void)  	if (IS_ERR(hba))  		return PTR_ERR(hba); -	lun0_hba = hba; -	t = hba->transport; - -	se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); -	if (!se_dev) { -		pr_err("Unable to allocate memory for" -				" struct se_subsystem_dev\n"); +	dev = target_alloc_device(hba, "virt_lun0"); +	if (!dev) {  		ret = -ENOMEM; -		goto out; +		goto out_free_hba;  	} -	INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); -	spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); -	INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); -	INIT_LIST_HEAD(&se_dev->t10_pr.aptpl_reg_list); -	spin_lock_init(&se_dev->t10_pr.registration_lock); -	spin_lock_init(&se_dev->t10_pr.aptpl_reg_lock); -	INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); -	spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); -	spin_lock_init(&se_dev->se_dev_lock); -	se_dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; -	se_dev->t10_wwn.t10_sub_dev = se_dev; -	se_dev->t10_alua.t10_sub_dev = se_dev; -	se_dev->se_dev_attrib.da_sub_dev = se_dev; -	se_dev->se_dev_hba = hba; - -	se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, "virt_lun0"); -	if (!se_dev->se_dev_su_ptr) { -		pr_err("Unable to locate subsystem dependent pointer" -			" from allocate_virtdevice()\n"); -		ret = -ENOMEM; -		goto out; -	} -	lun0_su_dev = se_dev;  	memset(buf, 0, 16);  	sprintf(buf, "rd_pages=8"); -	t->set_configfs_dev_params(hba, se_dev, buf, sizeof(buf)); +	hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf)); -	dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); -	if (IS_ERR(dev)) { -		ret = PTR_ERR(dev); -		goto out; -	} -	se_dev->se_dev_ptr = dev; -	g_lun0_dev = dev; +	ret = target_configure_device(dev); +	if (ret) +		goto out_free_se_dev; +	lun0_hba = hba; +	g_lun0_dev = dev;  	return 0; -out: -	lun0_su_dev = NULL; -	kfree(se_dev); -	if (lun0_hba) { -		core_delete_hba(lun0_hba); -		lun0_hba = NULL; -	} + +out_free_se_dev: +	target_free_device(dev); +out_free_hba: +	core_delete_hba(hba);  	return ret;  } @@ -1642,14 +1549,11 @@ out:  void core_dev_release_virtual_lun0(void)  {  	struct se_hba *hba = lun0_hba; -	struct se_subsystem_dev *su_dev = lun0_su_dev;  	if (!hba)  		return;  	if (g_lun0_dev) -		se_free_virtual_device(g_lun0_dev, hba); - -	kfree(su_dev); +		target_free_device(g_lun0_dev);  	core_delete_hba(hba);  } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index bca737bb813d..810263dfa4a1 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -4,10 +4,9 @@   * This file contains generic fabric module configfs infrastructure for   * TCM v4.x code   * - * Copyright (c) 2010,2011 Rising Tide Systems - * Copyright (c) 2010,2011 Linux-iSCSI.org + * (c) Copyright 2010-2012 RisingTide Systems LLC.   * - * Copyright (c) Nicholas A. Bellinger <[email protected]> + * Nicholas A. Bellinger <[email protected]>  *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -71,6 +70,12 @@ static int target_fabric_mappedlun_link(  	struct se_portal_group *se_tpg;  	struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s;  	int ret = 0, lun_access; + +	if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { +		pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" +			" %p to struct lun: %p\n", lun_ci, lun); +		return -EFAULT; +	}  	/*  	 * Ensure that the source port exists  	 */ @@ -358,7 +363,7 @@ static struct config_group *target_fabric_make_mappedlun(  	}  	lacl_cg = &lacl->se_lun_group; -	lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  				GFP_KERNEL);  	if (!lacl_cg->default_groups) {  		pr_err("Unable to allocate lacl_cg->default_groups\n"); @@ -374,7 +379,7 @@ static struct config_group *target_fabric_make_mappedlun(  	lacl_cg->default_groups[1] = NULL;  	ml_stat_grp = &lacl->ml_stat_grps.stat_group; -	ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, +	ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3,  				GFP_KERNEL);  	if (!ml_stat_grp->default_groups) {  		pr_err("Unable to allocate ml_stat_grp->default_groups\n"); @@ -734,17 +739,21 @@ static int target_fabric_port_link(  	struct config_item *se_dev_ci)  {  	struct config_item *tpg_ci; -	struct se_device *dev;  	struct se_lun *lun = container_of(to_config_group(lun_ci),  				struct se_lun, lun_group);  	struct se_lun *lun_p;  	struct se_portal_group *se_tpg; -	struct se_subsystem_dev *se_dev = container_of( -				to_config_group(se_dev_ci), struct se_subsystem_dev, -				se_dev_group); +	struct se_device *dev = +		container_of(to_config_group(se_dev_ci), struct se_device, dev_group);  	struct target_fabric_configfs *tf;  	int ret; +	if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { +		pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" +			" %p to struct se_device: %p\n", se_dev_ci, dev); +		return -EFAULT; +	} +  	tpg_ci = &lun_ci->ci_parent->ci_group->cg_item;  	se_tpg = container_of(to_config_group(tpg_ci),  				struct se_portal_group, tpg_group); @@ -755,14 +764,6 @@ static int target_fabric_port_link(  		return -EEXIST;  	} -	dev = se_dev->se_dev_ptr; -	if (!dev) { -		pr_err("Unable to locate struct se_device pointer from" -			" %s\n", config_item_name(se_dev_ci)); -		ret = -ENODEV; -		goto out; -	} -  	lun_p = core_dev_add_lun(se_tpg, dev, lun->unpacked_lun);  	if (IS_ERR(lun_p)) {  		pr_err("core_dev_add_lun() failed\n"); @@ -869,7 +870,7 @@ static struct config_group *target_fabric_make_lun(  		return ERR_PTR(-EINVAL);  	lun_cg = &lun->lun_group; -	lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, +	lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  				GFP_KERNEL);  	if (!lun_cg->default_groups) {  		pr_err("Unable to allocate lun_cg->default_groups\n"); diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index e460d6233a0a..687b0b0a4aa6 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -4,8 +4,7 @@   * This file contains generic high level protocol identifier and PR   * handlers for TCM fabric modules   * - * Copyright (c) 2010 Rising Tide Systems, Inc. - * Copyright (c) 2010 Linux-iSCSI.org + * (c) Copyright 2010-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 0360383dfb94..b9c88497e8f0 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -3,10 +3,7 @@   *   * This file contains the Storage Engine <-> FILEIO transport specific functions   * - * Copyright (c) 2005 PyX Technologies, Inc. - * Copyright (c) 2005-2006 SBE, Inc.  All Rights Reserved. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2005-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -41,7 +38,10 @@  #include "target_core_file.h" -static struct se_subsystem_api fileio_template; +static inline struct fd_dev *FD_DEV(struct se_device *dev) +{ +	return container_of(dev, struct fd_dev, dev); +}  /*	fd_attach_hba(): (Part of se_subsystem_api_t template)   * @@ -82,7 +82,7 @@ static void fd_detach_hba(struct se_hba *hba)  	hba->hba_ptr = NULL;  } -static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *fd_alloc_device(struct se_hba *hba, const char *name)  {  	struct fd_dev *fd_dev;  	struct fd_host *fd_host = hba->hba_ptr; @@ -97,34 +97,28 @@ static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name)  	pr_debug("FILEIO: Allocated fd_dev for %p\n", name); -	return fd_dev; +	return &fd_dev->dev;  } -/*	fd_create_virtdevice(): (Part of se_subsystem_api_t template) - * - * - */ -static struct se_device *fd_create_virtdevice( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	void *p) +static int fd_configure_device(struct se_device *dev)  { -	struct se_device *dev; -	struct se_dev_limits dev_limits; -	struct queue_limits *limits; -	struct fd_dev *fd_dev = p; -	struct fd_host *fd_host = hba->hba_ptr; +	struct fd_dev *fd_dev = FD_DEV(dev); +	struct fd_host *fd_host = dev->se_hba->hba_ptr;  	struct file *file;  	struct inode *inode = NULL; -	int dev_flags = 0, flags, ret = -EINVAL; +	int flags, ret = -EINVAL; -	memset(&dev_limits, 0, sizeof(struct se_dev_limits)); +	if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { +		pr_err("Missing fd_dev_name=\n"); +		return -EINVAL; +	}  	/*  	 * Use O_DSYNC by default instead of O_SYNC to forgo syncing  	 * of pure timestamp updates.  	 */  	flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; +  	/*  	 * Optionally allow fd_buffered_io=1 to be enabled for people  	 * who want use the fs buffer cache as an WriteCache mechanism. @@ -154,22 +148,17 @@ static struct se_device *fd_create_virtdevice(  	 */  	inode = file->f_mapping->host;  	if (S_ISBLK(inode->i_mode)) { -		struct request_queue *q; +		struct request_queue *q = bdev_get_queue(inode->i_bdev);  		unsigned long long dev_size; -		/* -		 * Setup the local scope queue_limits from struct request_queue->limits -		 * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. -		 */ -		q = bdev_get_queue(inode->i_bdev); -		limits = &dev_limits.limits; -		limits->logical_block_size = bdev_logical_block_size(inode->i_bdev); -		limits->max_hw_sectors = queue_max_hw_sectors(q); -		limits->max_sectors = queue_max_sectors(q); + +		dev->dev_attrib.hw_block_size = +			bdev_logical_block_size(inode->i_bdev); +		dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); +  		/*  		 * Determine the number of bytes from i_size_read() minus  		 * one (1) logical sector from underlying struct block_device  		 */ -		fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);  		dev_size = (i_size_read(file->f_mapping->host) -  				       fd_dev->fd_block_size); @@ -185,26 +174,18 @@ static struct se_device *fd_create_virtdevice(  			goto fail;  		} -		limits = &dev_limits.limits; -		limits->logical_block_size = FD_BLOCKSIZE; -		limits->max_hw_sectors = FD_MAX_SECTORS; -		limits->max_sectors = FD_MAX_SECTORS; -		fd_dev->fd_block_size = FD_BLOCKSIZE; +		dev->dev_attrib.hw_block_size = FD_BLOCKSIZE; +		dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS;  	} -	dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; -	dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH; +	fd_dev->fd_block_size = dev->dev_attrib.hw_block_size; -	dev = transport_add_device_to_core_hba(hba, &fileio_template, -				se_dev, dev_flags, fd_dev, -				&dev_limits, "FILEIO", FD_VERSION); -	if (!dev) -		goto fail; +	dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;  	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {  		pr_debug("FILEIO: Forcing setting of emulate_write_cache=1"  			" with FDBD_HAS_BUFFERED_IO_WCE\n"); -		dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1; +		dev->dev_attrib.emulate_write_cache = 1;  	}  	fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; @@ -214,22 +195,18 @@ static struct se_device *fd_create_virtdevice(  		" %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,  			fd_dev->fd_dev_name, fd_dev->fd_dev_size); -	return dev; +	return 0;  fail:  	if (fd_dev->fd_file) {  		filp_close(fd_dev->fd_file, NULL);  		fd_dev->fd_file = NULL;  	} -	return ERR_PTR(ret); +	return ret;  } -/*	fd_free_device(): (Part of se_subsystem_api_t template) - * - * - */ -static void fd_free_device(void *p) +static void fd_free_device(struct se_device *dev)  { -	struct fd_dev *fd_dev = p; +	struct fd_dev *fd_dev = FD_DEV(dev);  	if (fd_dev->fd_file) {  		filp_close(fd_dev->fd_file, NULL); @@ -239,17 +216,16 @@ static void fd_free_device(void *p)  	kfree(fd_dev);  } -static int fd_do_readv(struct se_cmd *cmd, struct scatterlist *sgl, -		u32 sgl_nents) +static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, +		u32 sgl_nents, int is_write)  {  	struct se_device *se_dev = cmd->se_dev; -	struct fd_dev *dev = se_dev->dev_ptr; +	struct fd_dev *dev = FD_DEV(se_dev);  	struct file *fd = dev->fd_file;  	struct scatterlist *sg;  	struct iovec *iov;  	mm_segment_t old_fs; -	loff_t pos = (cmd->t_task_lba * -		      se_dev->se_sub_dev->se_dev_attrib.block_size); +	loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size);  	int ret = 0, i;  	iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL); @@ -260,81 +236,58 @@ static int fd_do_readv(struct se_cmd *cmd, struct scatterlist *sgl,  	for_each_sg(sgl, sg, sgl_nents, i) {  		iov[i].iov_len = sg->length; -		iov[i].iov_base = sg_virt(sg); +		iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;  	}  	old_fs = get_fs();  	set_fs(get_ds()); -	ret = vfs_readv(fd, &iov[0], sgl_nents, &pos); + +	if (is_write) +		ret = vfs_writev(fd, &iov[0], sgl_nents, &pos); +	else +		ret = vfs_readv(fd, &iov[0], sgl_nents, &pos); +  	set_fs(old_fs); +	for_each_sg(sgl, sg, sgl_nents, i) +		kunmap(sg_page(sg)); +  	kfree(iov); -	/* -	 * Return zeros and GOOD status even if the READ did not return -	 * the expected virt_size for struct file w/o a backing struct -	 * block_device. -	 */ -	if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) { + +	if (is_write) {  		if (ret < 0 || ret != cmd->data_length) { -			pr_err("vfs_readv() returned %d," -				" expecting %d for S_ISBLK\n", ret, -				(int)cmd->data_length); +			pr_err("%s() write returned %d\n", __func__, ret);  			return (ret < 0 ? ret : -EINVAL);  		}  	} else { -		if (ret < 0) { -			pr_err("vfs_readv() returned %d for non" -				" S_ISBLK\n", ret); -			return ret; +		/* +		 * Return zeros and GOOD status even if the READ did not return +		 * the expected virt_size for struct file w/o a backing struct +		 * block_device. +		 */ +		if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) { +			if (ret < 0 || ret != cmd->data_length) { +				pr_err("%s() returned %d, expecting %u for " +						"S_ISBLK\n", __func__, ret, +						cmd->data_length); +				return (ret < 0 ? ret : -EINVAL); +			} +		} else { +			if (ret < 0) { +				pr_err("%s() returned %d for non S_ISBLK\n", +						__func__, ret); +				return ret; +			}  		}  	} - -	return 1; -} - -static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl, -		u32 sgl_nents) -{ -	struct se_device *se_dev = cmd->se_dev; -	struct fd_dev *dev = se_dev->dev_ptr; -	struct file *fd = dev->fd_file; -	struct scatterlist *sg; -	struct iovec *iov; -	mm_segment_t old_fs; -	loff_t pos = (cmd->t_task_lba * -		      se_dev->se_sub_dev->se_dev_attrib.block_size); -	int ret, i = 0; - -	iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL); -	if (!iov) { -		pr_err("Unable to allocate fd_do_writev iov[]\n"); -		return -ENOMEM; -	} - -	for_each_sg(sgl, sg, sgl_nents, i) { -		iov[i].iov_len = sg->length; -		iov[i].iov_base = sg_virt(sg); -	} - -	old_fs = get_fs(); -	set_fs(get_ds()); -	ret = vfs_writev(fd, &iov[0], sgl_nents, &pos); -	set_fs(old_fs); - -	kfree(iov); - -	if (ret < 0 || ret != cmd->data_length) { -		pr_err("vfs_writev() returned %d\n", ret); -		return (ret < 0 ? ret : -EINVAL); -	} -  	return 1;  } -static int fd_execute_sync_cache(struct se_cmd *cmd) +static sense_reason_t +fd_execute_sync_cache(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; -	struct fd_dev *fd_dev = dev->dev_ptr; +	struct fd_dev *fd_dev = FD_DEV(dev);  	int immed = (cmd->t_task_cdb[1] & 0x2);  	loff_t start, end;  	int ret; @@ -353,7 +306,7 @@ static int fd_execute_sync_cache(struct se_cmd *cmd)  		start = 0;  		end = LLONG_MAX;  	} else { -		start = cmd->t_task_lba * dev->se_sub_dev->se_dev_attrib.block_size; +		start = cmd->t_task_lba * dev->dev_attrib.block_size;  		if (cmd->data_length)  			end = start + cmd->data_length;  		else @@ -367,17 +320,16 @@ static int fd_execute_sync_cache(struct se_cmd *cmd)  	if (immed)  		return 0; -	if (ret) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	if (ret)  		target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); -	} else { +	else  		target_complete_cmd(cmd, SAM_STAT_GOOD); -	}  	return 0;  } -static int fd_execute_rw(struct se_cmd *cmd) +static sense_reason_t +fd_execute_rw(struct se_cmd *cmd)  {  	struct scatterlist *sgl = cmd->t_data_sg;  	u32 sgl_nents = cmd->t_data_nents; @@ -390,30 +342,29 @@ static int fd_execute_rw(struct se_cmd *cmd)  	 * physical memory addresses to struct iovec virtual memory.  	 */  	if (data_direction == DMA_FROM_DEVICE) { -		ret = fd_do_readv(cmd, sgl, sgl_nents); +		ret = fd_do_rw(cmd, sgl, sgl_nents, 0);  	} else { -		ret = fd_do_writev(cmd, sgl, sgl_nents); +		ret = fd_do_rw(cmd, sgl, sgl_nents, 1);  		/*  		 * Perform implict vfs_fsync_range() for fd_do_writev() ops  		 * for SCSI WRITEs with Forced Unit Access (FUA) set.  		 * Allow this to happen independent of WCE=0 setting.  		 */  		if (ret > 0 && -		    dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && +		    dev->dev_attrib.emulate_fua_write > 0 &&  		    (cmd->se_cmd_flags & SCF_FUA)) { -			struct fd_dev *fd_dev = dev->dev_ptr; +			struct fd_dev *fd_dev = FD_DEV(dev);  			loff_t start = cmd->t_task_lba * -				dev->se_sub_dev->se_dev_attrib.block_size; +				dev->dev_attrib.block_size;  			loff_t end = start + cmd->data_length;  			vfs_fsync_range(fd_dev->fd_file, start, end, 1);  		}  	} -	if (ret < 0) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return ret; -	} +	if (ret < 0) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +  	if (ret)  		target_complete_cmd(cmd, SAM_STAT_GOOD);  	return 0; @@ -430,12 +381,10 @@ static match_table_t tokens = {  	{Opt_err, NULL}  }; -static ssize_t fd_set_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	const char *page, ssize_t count) +static ssize_t fd_set_configfs_dev_params(struct se_device *dev, +		const char *page, ssize_t count)  { -	struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; +	struct fd_dev *fd_dev = FD_DEV(dev);  	char *orig, *ptr, *arg_p, *opts;  	substring_t args[MAX_OPT_ARGS];  	int ret = 0, arg, token; @@ -502,24 +451,9 @@ out:  	return (!ret) ? count : ret;  } -static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) +static ssize_t fd_show_configfs_dev_params(struct se_device *dev, char *b)  { -	struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; - -	if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { -		pr_err("Missing fd_dev_name=\n"); -		return -EINVAL; -	} - -	return 0; -} - -static ssize_t fd_show_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	char *b) -{ -	struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; +	struct fd_dev *fd_dev = FD_DEV(dev);  	ssize_t bl = 0;  	bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); @@ -530,27 +464,9 @@ static ssize_t fd_show_configfs_dev_params(  	return bl;  } -/*	fd_get_device_rev(): (Part of se_subsystem_api_t template) - * - * - */ -static u32 fd_get_device_rev(struct se_device *dev) -{ -	return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ -} - -/*	fd_get_device_type(): (Part of se_subsystem_api_t template) - * - * - */ -static u32 fd_get_device_type(struct se_device *dev) -{ -	return TYPE_DISK; -} -  static sector_t fd_get_blocks(struct se_device *dev)  { -	struct fd_dev *fd_dev = dev->dev_ptr; +	struct fd_dev *fd_dev = FD_DEV(dev);  	struct file *f = fd_dev->fd_file;  	struct inode *i = f->f_mapping->host;  	unsigned long long dev_size; @@ -564,34 +480,35 @@ static sector_t fd_get_blocks(struct se_device *dev)  	else  		dev_size = fd_dev->fd_dev_size; -	return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size); +	return div_u64(dev_size, dev->dev_attrib.block_size);  } -static struct spc_ops fd_spc_ops = { +static struct sbc_ops fd_sbc_ops = {  	.execute_rw		= fd_execute_rw,  	.execute_sync_cache	= fd_execute_sync_cache,  }; -static int fd_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +fd_parse_cdb(struct se_cmd *cmd)  { -	return sbc_parse_cdb(cmd, &fd_spc_ops); +	return sbc_parse_cdb(cmd, &fd_sbc_ops);  }  static struct se_subsystem_api fileio_template = {  	.name			= "fileio", +	.inquiry_prod		= "FILEIO", +	.inquiry_rev		= FD_VERSION,  	.owner			= THIS_MODULE,  	.transport_type		= TRANSPORT_PLUGIN_VHBA_PDEV,  	.attach_hba		= fd_attach_hba,  	.detach_hba		= fd_detach_hba, -	.allocate_virtdevice	= fd_allocate_virtdevice, -	.create_virtdevice	= fd_create_virtdevice, +	.alloc_device		= fd_alloc_device, +	.configure_device	= fd_configure_device,  	.free_device		= fd_free_device,  	.parse_cdb		= fd_parse_cdb, -	.check_configfs_dev_params = fd_check_configfs_dev_params,  	.set_configfs_dev_params = fd_set_configfs_dev_params,  	.show_configfs_dev_params = fd_show_configfs_dev_params, -	.get_device_rev		= fd_get_device_rev, -	.get_device_type	= fd_get_device_type, +	.get_device_type	= sbc_get_device_type,  	.get_blocks		= fd_get_blocks,  }; diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 876ae53ef5b8..bc02b018ae46 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h @@ -17,6 +17,8 @@  #define FDBD_HAS_BUFFERED_IO_WCE 0x04  struct fd_dev { +	struct se_device dev; +  	u32		fbd_flags;  	unsigned char	fd_dev_name[FD_MAX_DEV_NAME];  	/* Unique Ramdisk Device ID in Ramdisk HBA */ diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 3dd1bd4b6f71..d2616cd48f1e 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -3,10 +3,7 @@   *   * This file contains the TCM HBA Transport related functions.   * - * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2003-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -113,7 +110,6 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags)  		return ERR_PTR(-ENOMEM);  	} -	INIT_LIST_HEAD(&hba->hba_dev_list);  	spin_lock_init(&hba->device_lock);  	mutex_init(&hba->hba_access_mutex); @@ -152,8 +148,7 @@ out_free_hba:  int  core_delete_hba(struct se_hba *hba)  { -	if (!list_empty(&hba->hba_dev_list)) -		dump_stack(); +	WARN_ON(hba->dev_count);  	hba->transport->detach_hba(hba); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 57d7674c5013..b526d23dcd4f 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -4,10 +4,7 @@   * This file contains the Storage Engine  <-> Linux BlockIO transport   * specific functions.   * - * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2003-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -50,9 +47,13 @@  #define IBLOCK_MAX_BIO_PER_TASK	 32	/* max # of bios to submit at a time */  #define IBLOCK_BIO_POOL_SIZE	128 -static struct se_subsystem_api iblock_template; +static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev) +{ +	return container_of(dev, struct iblock_dev, dev); +} + -static void iblock_bio_done(struct bio *, int); +static struct se_subsystem_api iblock_template;  /*	iblock_attach_hba(): (Part of se_subsystem_api_t template)   * @@ -70,7 +71,7 @@ static void iblock_detach_hba(struct se_hba *hba)  {  } -static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *iblock_alloc_device(struct se_hba *hba, const char *name)  {  	struct iblock_dev *ib_dev = NULL; @@ -82,40 +83,28 @@ static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name)  	pr_debug( "IBLOCK: Allocated ib_dev for %s\n", name); -	return ib_dev; +	return &ib_dev->dev;  } -static struct se_device *iblock_create_virtdevice( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	void *p) +static int iblock_configure_device(struct se_device *dev)  { -	struct iblock_dev *ib_dev = p; -	struct se_device *dev; -	struct se_dev_limits dev_limits; -	struct block_device *bd = NULL; +	struct iblock_dev *ib_dev = IBLOCK_DEV(dev);  	struct request_queue *q; -	struct queue_limits *limits; -	u32 dev_flags = 0; +	struct block_device *bd = NULL;  	fmode_t mode; -	int ret = -EINVAL; +	int ret = -ENOMEM; -	if (!ib_dev) { -		pr_err("Unable to locate struct iblock_dev parameter\n"); -		return ERR_PTR(ret); +	if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) { +		pr_err("Missing udev_path= parameters for IBLOCK\n"); +		return -EINVAL;  	} -	memset(&dev_limits, 0, sizeof(struct se_dev_limits));  	ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0);  	if (!ib_dev->ibd_bio_set) { -		pr_err("IBLOCK: Unable to create bioset()\n"); -		return ERR_PTR(-ENOMEM); +		pr_err("IBLOCK: Unable to create bioset\n"); +		goto out;  	} -	pr_debug("IBLOCK: Created bio_set()\n"); -	/* -	 * iblock_check_configfs_dev_params() ensures that ib_dev->ibd_udev_path -	 * must already have been set in order for echo 1 > $HBA/$DEV/enable to run. -	 */ +  	pr_debug( "IBLOCK: Claiming struct block_device: %s\n",  			ib_dev->ibd_udev_path); @@ -126,27 +115,15 @@ static struct se_device *iblock_create_virtdevice(  	bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev);  	if (IS_ERR(bd)) {  		ret = PTR_ERR(bd); -		goto failed; +		goto out_free_bioset;  	} -	/* -	 * Setup the local scope queue_limits from struct request_queue->limits -	 * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. -	 */ -	q = bdev_get_queue(bd); -	limits = &dev_limits.limits; -	limits->logical_block_size = bdev_logical_block_size(bd); -	limits->max_hw_sectors = UINT_MAX; -	limits->max_sectors = UINT_MAX; -	dev_limits.hw_queue_depth = q->nr_requests; -	dev_limits.queue_depth = q->nr_requests; -  	ib_dev->ibd_bd = bd; -	dev = transport_add_device_to_core_hba(hba, -			&iblock_template, se_dev, dev_flags, ib_dev, -			&dev_limits, "IBLOCK", IBLOCK_VERSION); -	if (!dev) -		goto failed; +	q = bdev_get_queue(bd); + +	dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); +	dev->dev_attrib.hw_max_sectors = UINT_MAX; +	dev->dev_attrib.hw_queue_depth = q->nr_requests;  	/*  	 * Check if the underlying struct block_device request_queue supports @@ -154,38 +131,41 @@ static struct se_device *iblock_create_virtdevice(  	 * in ATA and we need to set TPE=1  	 */  	if (blk_queue_discard(q)) { -		dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count = +		dev->dev_attrib.max_unmap_lba_count =  				q->limits.max_discard_sectors; +  		/*  		 * Currently hardcoded to 1 in Linux/SCSI code..  		 */ -		dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = 1; -		dev->se_sub_dev->se_dev_attrib.unmap_granularity = +		dev->dev_attrib.max_unmap_block_desc_count = 1; +		dev->dev_attrib.unmap_granularity =  				q->limits.discard_granularity >> 9; -		dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = +		dev->dev_attrib.unmap_granularity_alignment =  				q->limits.discard_alignment;  		pr_debug("IBLOCK: BLOCK Discard support available,"  				" disabled by default\n");  	} +	/* +	 * Enable write same emulation for IBLOCK and use 0xFFFF as +	 * the smaller WRITE_SAME(10) only has a two-byte block count. +	 */ +	dev->dev_attrib.max_write_same_len = 0xFFFF;  	if (blk_queue_nonrot(q)) -		dev->se_sub_dev->se_dev_attrib.is_nonrot = 1; - -	return dev; +		dev->dev_attrib.is_nonrot = 1; +	return 0; -failed: -	if (ib_dev->ibd_bio_set) { -		bioset_free(ib_dev->ibd_bio_set); -		ib_dev->ibd_bio_set = NULL; -	} -	ib_dev->ibd_bd = NULL; -	return ERR_PTR(ret); +out_free_bioset: +	bioset_free(ib_dev->ibd_bio_set); +	ib_dev->ibd_bio_set = NULL; +out: +	return ret;  } -static void iblock_free_device(void *p) +static void iblock_free_device(struct se_device *dev)  { -	struct iblock_dev *ib_dev = p; +	struct iblock_dev *ib_dev = IBLOCK_DEV(dev);  	if (ib_dev->ibd_bd != NULL)  		blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); @@ -203,12 +183,12 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(  					bdev_logical_block_size(bd)) - 1);  	u32 block_size = bdev_logical_block_size(bd); -	if (block_size == dev->se_sub_dev->se_dev_attrib.block_size) +	if (block_size == dev->dev_attrib.block_size)  		return blocks_long;  	switch (block_size) {  	case 4096: -		switch (dev->se_sub_dev->se_dev_attrib.block_size) { +		switch (dev->dev_attrib.block_size) {  		case 2048:  			blocks_long <<= 1;  			break; @@ -222,7 +202,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(  		}  		break;  	case 2048: -		switch (dev->se_sub_dev->se_dev_attrib.block_size) { +		switch (dev->dev_attrib.block_size) {  		case 4096:  			blocks_long >>= 1;  			break; @@ -237,7 +217,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(  		}  		break;  	case 1024: -		switch (dev->se_sub_dev->se_dev_attrib.block_size) { +		switch (dev->dev_attrib.block_size) {  		case 4096:  			blocks_long >>= 2;  			break; @@ -252,7 +232,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(  		}  		break;  	case 512: -		switch (dev->se_sub_dev->se_dev_attrib.block_size) { +		switch (dev->dev_attrib.block_size) {  		case 4096:  			blocks_long >>= 3;  			break; @@ -273,6 +253,87 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(  	return blocks_long;  } +static void iblock_complete_cmd(struct se_cmd *cmd) +{ +	struct iblock_req *ibr = cmd->priv; +	u8 status; + +	if (!atomic_dec_and_test(&ibr->pending)) +		return; + +	if (atomic_read(&ibr->ib_bio_err_cnt)) +		status = SAM_STAT_CHECK_CONDITION; +	else +		status = SAM_STAT_GOOD; + +	target_complete_cmd(cmd, status); +	kfree(ibr); +} + +static void iblock_bio_done(struct bio *bio, int err) +{ +	struct se_cmd *cmd = bio->bi_private; +	struct iblock_req *ibr = cmd->priv; + +	/* +	 * Set -EIO if !BIO_UPTODATE and the passed is still err=0 +	 */ +	if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) +		err = -EIO; + +	if (err != 0) { +		pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," +			" err: %d\n", bio, err); +		/* +		 * Bump the ib_bio_err_cnt and release bio. +		 */ +		atomic_inc(&ibr->ib_bio_err_cnt); +		smp_mb__after_atomic_inc(); +	} + +	bio_put(bio); + +	iblock_complete_cmd(cmd); +} + +static struct bio * +iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) +{ +	struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); +	struct bio *bio; + +	/* +	 * Only allocate as many vector entries as the bio code allows us to, +	 * we'll loop later on until we have handled the whole request. +	 */ +	if (sg_num > BIO_MAX_PAGES) +		sg_num = BIO_MAX_PAGES; + +	bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); +	if (!bio) { +		pr_err("Unable to allocate memory for bio\n"); +		return NULL; +	} + +	bio->bi_bdev = ib_dev->ibd_bd; +	bio->bi_private = cmd; +	bio->bi_end_io = &iblock_bio_done; +	bio->bi_sector = lba; + +	return bio; +} + +static void iblock_submit_bios(struct bio_list *list, int rw) +{ +	struct blk_plug plug; +	struct bio *bio; + +	blk_start_plug(&plug); +	while ((bio = bio_list_pop(list))) +		submit_bio(rw, bio); +	blk_finish_plug(&plug); +} +  static void iblock_end_io_flush(struct bio *bio, int err)  {  	struct se_cmd *cmd = bio->bi_private; @@ -281,13 +342,10 @@ static void iblock_end_io_flush(struct bio *bio, int err)  		pr_err("IBLOCK: cache flush failed: %d\n", err);  	if (cmd) { -		if (err) { -			cmd->scsi_sense_reason = -				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		if (err)  			target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); -		} else { +		else  			target_complete_cmd(cmd, SAM_STAT_GOOD); -		}  	}  	bio_put(bio); @@ -297,9 +355,10 @@ static void iblock_end_io_flush(struct bio *bio, int err)   * Implement SYCHRONIZE CACHE.  Note that we can't handle lba ranges and must   * always flush the whole cache.   */ -static int iblock_execute_sync_cache(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_sync_cache(struct se_cmd *cmd)  { -	struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; +	struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);  	int immed = (cmd->t_task_cdb[1] & 0x2);  	struct bio *bio; @@ -319,25 +378,27 @@ static int iblock_execute_sync_cache(struct se_cmd *cmd)  	return 0;  } -static int iblock_execute_unmap(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_unmap(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; -	struct iblock_dev *ibd = dev->dev_ptr; +	struct iblock_dev *ib_dev = IBLOCK_DEV(dev);  	unsigned char *buf, *ptr = NULL;  	sector_t lba;  	int size;  	u32 range; -	int ret = 0; -	int dl, bd_dl; +	sense_reason_t ret = 0; +	int dl, bd_dl, err;  	if (cmd->data_length < 8) {  		pr_warn("UNMAP parameter list length %u too small\n",  			cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		return TCM_INVALID_PARAMETER_LIST;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	dl = get_unaligned_be16(&buf[0]);  	bd_dl = get_unaligned_be16(&buf[2]); @@ -349,9 +410,8 @@ static int iblock_execute_unmap(struct se_cmd *cmd)  	else  		size = bd_dl; -	if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +	if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { +		ret = TCM_INVALID_PARAMETER_LIST;  		goto err;  	} @@ -366,23 +426,22 @@ static int iblock_execute_unmap(struct se_cmd *cmd)  		pr_debug("UNMAP: Using lba: %llu and range: %u\n",  				 (unsigned long long)lba, range); -		if (range > dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count) { -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			ret = -EINVAL; +		if (range > dev->dev_attrib.max_unmap_lba_count) { +			ret = TCM_INVALID_PARAMETER_LIST;  			goto err;  		}  		if (lba + range > dev->transport->get_blocks(dev) + 1) { -			cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE; -			ret = -EINVAL; +			ret = TCM_ADDRESS_OUT_OF_RANGE;  			goto err;  		} -		ret = blkdev_issue_discard(ibd->ibd_bd, lba, range, +		err = blkdev_issue_discard(ib_dev->ibd_bd, lba, range,  					   GFP_KERNEL, 0); -		if (ret < 0) { +		if (err < 0) {  			pr_err("blkdev_issue_discard() failed: %d\n", -					ret); +					err); +			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  			goto err;  		} @@ -397,23 +456,86 @@ err:  	return ret;  } -static int iblock_execute_write_same(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_write_same_unmap(struct se_cmd *cmd)  { -	struct iblock_dev *ibd = cmd->se_dev->dev_ptr; -	int ret; - -	ret = blkdev_issue_discard(ibd->ibd_bd, cmd->t_task_lba, -				   spc_get_write_same_sectors(cmd), GFP_KERNEL, -				   0); -	if (ret < 0) { -		pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); -		return ret; +	struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); +	int rc; + +	rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, +			spc_get_write_same_sectors(cmd), GFP_KERNEL, 0); +	if (rc < 0) { +		pr_warn("blkdev_issue_discard() failed: %d\n", rc); +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	target_complete_cmd(cmd, GOOD);  	return 0;  } +static sense_reason_t +iblock_execute_write_same(struct se_cmd *cmd) +{ +	struct iblock_req *ibr; +	struct scatterlist *sg; +	struct bio *bio; +	struct bio_list list; +	sector_t block_lba = cmd->t_task_lba; +	sector_t sectors = spc_get_write_same_sectors(cmd); + +	sg = &cmd->t_data_sg[0]; + +	if (cmd->t_data_nents > 1 || +	    sg->length != cmd->se_dev->dev_attrib.block_size) { +		pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" +			" block_size: %u\n", cmd->t_data_nents, sg->length, +			cmd->se_dev->dev_attrib.block_size); +		return TCM_INVALID_CDB_FIELD; +	} + +	ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); +	if (!ibr) +		goto fail; +	cmd->priv = ibr; + +	bio = iblock_get_bio(cmd, block_lba, 1); +	if (!bio) +		goto fail_free_ibr; + +	bio_list_init(&list); +	bio_list_add(&list, bio); + +	atomic_set(&ibr->pending, 1); + +	while (sectors) { +		while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) +				!= sg->length) { + +			bio = iblock_get_bio(cmd, block_lba, 1); +			if (!bio) +				goto fail_put_bios; + +			atomic_inc(&ibr->pending); +			bio_list_add(&list, bio); +		} + +		/* Always in 512 byte units for Linux/Block */ +		block_lba += sg->length >> IBLOCK_LBA_SHIFT; +		sectors -= 1; +	} + +	iblock_submit_bios(&list, WRITE); +	return 0; + +fail_put_bios: +	while ((bio = bio_list_pop(&list))) +		bio_put(bio); +fail_free_ibr: +	kfree(ibr); +fail: +	return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +} +  enum {  	Opt_udev_path, Opt_readonly, Opt_force, Opt_err  }; @@ -425,11 +547,10 @@ static match_table_t tokens = {  	{Opt_err, NULL}  }; -static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, -					       struct se_subsystem_dev *se_dev, -					       const char *page, ssize_t count) +static ssize_t iblock_set_configfs_dev_params(struct se_device *dev, +		const char *page, ssize_t count)  { -	struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; +	struct iblock_dev *ib_dev = IBLOCK_DEV(dev);  	char *orig, *ptr, *arg_p, *opts;  	substring_t args[MAX_OPT_ARGS];  	int ret = 0, token; @@ -491,43 +612,26 @@ out:  	return (!ret) ? count : ret;  } -static ssize_t iblock_check_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev) +static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)  { -	struct iblock_dev *ibd = se_dev->se_dev_su_ptr; - -	if (!(ibd->ibd_flags & IBDF_HAS_UDEV_PATH)) { -		pr_err("Missing udev_path= parameters for IBLOCK\n"); -		return -EINVAL; -	} - -	return 0; -} - -static ssize_t iblock_show_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	char *b) -{ -	struct iblock_dev *ibd = se_dev->se_dev_su_ptr; -	struct block_device *bd = ibd->ibd_bd; +	struct iblock_dev *ib_dev = IBLOCK_DEV(dev); +	struct block_device *bd = ib_dev->ibd_bd;  	char buf[BDEVNAME_SIZE];  	ssize_t bl = 0;  	if (bd)  		bl += sprintf(b + bl, "iBlock device: %s",  				bdevname(bd, buf)); -	if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) +	if (ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)  		bl += sprintf(b + bl, "  UDEV PATH: %s", -				ibd->ibd_udev_path); -	bl += sprintf(b + bl, "  readonly: %d\n", ibd->ibd_readonly); +				ib_dev->ibd_udev_path); +	bl += sprintf(b + bl, "  readonly: %d\n", ib_dev->ibd_readonly);  	bl += sprintf(b + bl, "        ");  	if (bd) {  		bl += sprintf(b + bl, "Major: %d Minor: %d  %s\n",  			MAJOR(bd->bd_dev), MINOR(bd->bd_dev), (!bd->bd_contains) ? -			"" : (bd->bd_holder == ibd) ? +			"" : (bd->bd_holder == ib_dev) ?  			"CLAIMED: IBLOCK" : "CLAIMED: OS");  	} else {  		bl += sprintf(b + bl, "Major: 0 Minor: 0\n"); @@ -536,61 +640,8 @@ static ssize_t iblock_show_configfs_dev_params(  	return bl;  } -static void iblock_complete_cmd(struct se_cmd *cmd) -{ -	struct iblock_req *ibr = cmd->priv; -	u8 status; - -	if (!atomic_dec_and_test(&ibr->pending)) -		return; - -	if (atomic_read(&ibr->ib_bio_err_cnt)) -		status = SAM_STAT_CHECK_CONDITION; -	else -		status = SAM_STAT_GOOD; - -	target_complete_cmd(cmd, status); -	kfree(ibr); -} - -static struct bio * -iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) -{ -	struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; -	struct bio *bio; - -	/* -	 * Only allocate as many vector entries as the bio code allows us to, -	 * we'll loop later on until we have handled the whole request. -	 */ -	if (sg_num > BIO_MAX_PAGES) -		sg_num = BIO_MAX_PAGES; - -	bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); -	if (!bio) { -		pr_err("Unable to allocate memory for bio\n"); -		return NULL; -	} - -	bio->bi_bdev = ib_dev->ibd_bd; -	bio->bi_private = cmd; -	bio->bi_end_io = &iblock_bio_done; -	bio->bi_sector = lba; -	return bio; -} - -static void iblock_submit_bios(struct bio_list *list, int rw) -{ -	struct blk_plug plug; -	struct bio *bio; - -	blk_start_plug(&plug); -	while ((bio = bio_list_pop(list))) -		submit_bio(rw, bio); -	blk_finish_plug(&plug); -} - -static int iblock_execute_rw(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_rw(struct se_cmd *cmd)  {  	struct scatterlist *sgl = cmd->t_data_sg;  	u32 sgl_nents = cmd->t_data_nents; @@ -611,8 +662,8 @@ static int iblock_execute_rw(struct se_cmd *cmd)  		 * Force data to disk if we pretend to not have a volatile  		 * write cache, or the initiator set the Force Unit Access bit.  		 */ -		if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 || -		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && +		if (dev->dev_attrib.emulate_write_cache == 0 || +		    (dev->dev_attrib.emulate_fua_write > 0 &&  		     (cmd->se_cmd_flags & SCF_FUA)))  			rw = WRITE_FUA;  		else @@ -625,19 +676,18 @@ static int iblock_execute_rw(struct se_cmd *cmd)  	 * Convert the blocksize advertised to the initiator to the 512 byte  	 * units unconditionally used by the Linux block layer.  	 */ -	if (dev->se_sub_dev->se_dev_attrib.block_size == 4096) +	if (dev->dev_attrib.block_size == 4096)  		block_lba = (cmd->t_task_lba << 3); -	else if (dev->se_sub_dev->se_dev_attrib.block_size == 2048) +	else if (dev->dev_attrib.block_size == 2048)  		block_lba = (cmd->t_task_lba << 2); -	else if (dev->se_sub_dev->se_dev_attrib.block_size == 1024) +	else if (dev->dev_attrib.block_size == 1024)  		block_lba = (cmd->t_task_lba << 1); -	else if (dev->se_sub_dev->se_dev_attrib.block_size == 512) +	else if (dev->dev_attrib.block_size == 512)  		block_lba = cmd->t_task_lba;  	else {  		pr_err("Unsupported SCSI -> BLOCK LBA conversion:" -				" %u\n", dev->se_sub_dev->se_dev_attrib.block_size); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -ENOSYS; +				" %u\n", dev->dev_attrib.block_size); +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); @@ -697,83 +747,48 @@ fail_put_bios:  		bio_put(bio);  fail_free_ibr:  	kfree(ibr); -	cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  fail: -	return -ENOMEM; -} - -static u32 iblock_get_device_rev(struct se_device *dev) -{ -	return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ -} - -static u32 iblock_get_device_type(struct se_device *dev) -{ -	return TYPE_DISK; +	return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  }  static sector_t iblock_get_blocks(struct se_device *dev)  { -	struct iblock_dev *ibd = dev->dev_ptr; -	struct block_device *bd = ibd->ibd_bd; +	struct iblock_dev *ib_dev = IBLOCK_DEV(dev); +	struct block_device *bd = ib_dev->ibd_bd;  	struct request_queue *q = bdev_get_queue(bd);  	return iblock_emulate_read_cap_with_block_size(dev, bd, q);  } -static void iblock_bio_done(struct bio *bio, int err) -{ -	struct se_cmd *cmd = bio->bi_private; -	struct iblock_req *ibr = cmd->priv; - -	/* -	 * Set -EIO if !BIO_UPTODATE and the passed is still err=0 -	 */ -	if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) -		err = -EIO; - -	if (err != 0) { -		pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," -			" err: %d\n", bio, err); -		/* -		 * Bump the ib_bio_err_cnt and release bio. -		 */ -		atomic_inc(&ibr->ib_bio_err_cnt); -		smp_mb__after_atomic_inc(); -	} - -	bio_put(bio); - -	iblock_complete_cmd(cmd); -} - -static struct spc_ops iblock_spc_ops = { +static struct sbc_ops iblock_sbc_ops = {  	.execute_rw		= iblock_execute_rw,  	.execute_sync_cache	= iblock_execute_sync_cache,  	.execute_write_same	= iblock_execute_write_same, +	.execute_write_same_unmap = iblock_execute_write_same_unmap,  	.execute_unmap		= iblock_execute_unmap,  }; -static int iblock_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +iblock_parse_cdb(struct se_cmd *cmd)  { -	return sbc_parse_cdb(cmd, &iblock_spc_ops); +	return sbc_parse_cdb(cmd, &iblock_sbc_ops);  }  static struct se_subsystem_api iblock_template = {  	.name			= "iblock", +	.inquiry_prod		= "IBLOCK", +	.inquiry_rev		= IBLOCK_VERSION,  	.owner			= THIS_MODULE,  	.transport_type		= TRANSPORT_PLUGIN_VHBA_PDEV,  	.attach_hba		= iblock_attach_hba,  	.detach_hba		= iblock_detach_hba, -	.allocate_virtdevice	= iblock_allocate_virtdevice, -	.create_virtdevice	= iblock_create_virtdevice, +	.alloc_device		= iblock_alloc_device, +	.configure_device	= iblock_configure_device,  	.free_device		= iblock_free_device,  	.parse_cdb		= iblock_parse_cdb, -	.check_configfs_dev_params = iblock_check_configfs_dev_params,  	.set_configfs_dev_params = iblock_set_configfs_dev_params,  	.show_configfs_dev_params = iblock_show_configfs_dev_params, -	.get_device_rev		= iblock_get_device_rev, -	.get_device_type	= iblock_get_device_type, +	.get_device_type	= sbc_get_device_type,  	.get_blocks		= iblock_get_blocks,  }; diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 533627ae79ec..01c2afd81500 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -14,6 +14,7 @@ struct iblock_req {  #define IBDF_HAS_UDEV_PATH		0x01  struct iblock_dev { +	struct se_device dev;  	unsigned char ibd_udev_path[SE_UDEV_PATH_LEN];  	u32	ibd_flags;  	struct bio_set	*ibd_bio_set; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 0fd428225d11..93e9c1f580b0 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -19,18 +19,12 @@ int	core_dev_export(struct se_device *, struct se_portal_group *,  		struct se_lun *);  void	core_dev_unexport(struct se_device *, struct se_portal_group *,  		struct se_lun *); -int	target_report_luns(struct se_cmd *); -void	se_release_device_for_hba(struct se_device *); -void	se_release_vpd_for_dev(struct se_device *); -int	se_free_virtual_device(struct se_device *, struct se_hba *); -int	se_dev_check_online(struct se_device *); -int	se_dev_check_shutdown(struct se_device *); -void	se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *);  int	se_dev_set_task_timeout(struct se_device *, u32);  int	se_dev_set_max_unmap_lba_count(struct se_device *, u32);  int	se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);  int	se_dev_set_unmap_granularity(struct se_device *, u32);  int	se_dev_set_unmap_granularity_alignment(struct se_device *, u32); +int	se_dev_set_max_write_same_len(struct se_device *, u32);  int	se_dev_set_emulate_dpo(struct se_device *, int);  int	se_dev_set_emulate_fua_write(struct se_device *, int);  int	se_dev_set_emulate_fua_read(struct se_device *, int); @@ -60,6 +54,9 @@ void	core_dev_free_initiator_node_lun_acl(struct se_portal_group *,  		struct se_lun_acl *lacl);  int	core_dev_setup_virtual_lun0(void);  void	core_dev_release_virtual_lun0(void); +struct se_device *target_alloc_device(struct se_hba *hba, const char *name); +int	target_configure_device(struct se_device *dev); +void	target_free_device(struct se_device *);  /* target_core_hba.c */  struct se_hba *core_alloc_hba(const char *, u32, u32); @@ -105,10 +102,11 @@ int	transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);  bool	target_stop_cmd(struct se_cmd *cmd, unsigned long *flags);  int	transport_clear_lun_from_sessions(struct se_lun *);  void	transport_send_task_abort(struct se_cmd *); -int	target_cmd_size_check(struct se_cmd *cmd, unsigned int size); +sense_reason_t	target_cmd_size_check(struct se_cmd *cmd, unsigned int size); +void	target_qf_do_work(struct work_struct *work);  /* target_core_stat.c */ -void	target_stat_setup_dev_default_groups(struct se_subsystem_dev *); +void	target_stat_setup_dev_default_groups(struct se_device *);  void	target_stat_setup_port_default_groups(struct se_lun *);  void	target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 8c323a98c4a0..e35dbf85841f 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -4,8 +4,7 @@   * This file contains SPC-3 compliant persistent reservations and   * legacy SPC-2 reservations with compatible reservation handling (CRH=1)   * - * Copyright (c) 2009, 2010 Rising Tide Systems - * Copyright (c) 2009, 2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -68,49 +67,33 @@ int core_pr_dump_initiator_port(  static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,  			struct t10_pr_registration *, int); -static int core_scsi2_reservation_seq_non_holder( -	struct se_cmd *cmd, -	unsigned char *cdb, -	u32 pr_reg_type) +static sense_reason_t +target_scsi2_reservation_check(struct se_cmd *cmd)  { -	switch (cdb[0]) { +	struct se_device *dev = cmd->se_dev; +	struct se_session *sess = cmd->se_sess; + +	switch (cmd->t_task_cdb[0]) {  	case INQUIRY:  	case RELEASE:  	case RELEASE_10:  		return 0;  	default: -		return 1; +		break;  	} -	return 1; -} - -static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) -{ -	struct se_device *dev = cmd->se_dev; -	struct se_session *sess = cmd->se_sess; -	int ret; - -	if (!sess) +	if (!dev->dev_reserved_node_acl || !sess)  		return 0; -	spin_lock(&dev->dev_reservation_lock); -	if (!dev->dev_reserved_node_acl || !sess) { -		spin_unlock(&dev->dev_reservation_lock); -		return 0; -	} -	if (dev->dev_reserved_node_acl != sess->se_node_acl) { -		spin_unlock(&dev->dev_reservation_lock); -		return -EINVAL; -	} -	if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) { -		spin_unlock(&dev->dev_reservation_lock); -		return 0; +	if (dev->dev_reserved_node_acl != sess->se_node_acl) +		return TCM_RESERVATION_CONFLICT; + +	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS_WITH_ISID) { +		if (dev->dev_res_bin_isid != sess->sess_bin_isid) +			return TCM_RESERVATION_CONFLICT;  	} -	ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -EINVAL; -	spin_unlock(&dev->dev_reservation_lock); -	return ret; +	return 0;  }  static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, @@ -120,15 +103,11 @@ static void core_scsi3_put_pr_reg(struct t10_pr_registration *);  static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd)  {  	struct se_session *se_sess = cmd->se_sess; -	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; +	struct se_device *dev = cmd->se_dev;  	struct t10_pr_registration *pr_reg; -	struct t10_reservation *pr_tmpl = &su_dev->t10_pr; -	int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	int conflict = 0; -	if (!crh) -		return -EINVAL; -  	pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,  			se_sess);  	if (pr_reg) { @@ -186,32 +165,28 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd)  		pr_err("Received legacy SPC-2 RESERVE/RELEASE"  			" while active SPC-3 registrations exist,"  			" returning RESERVATION_CONFLICT\n"); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;  		return -EBUSY;  	}  	return 0;  } -int target_scsi2_reservation_release(struct se_cmd *cmd) +sense_reason_t +target_scsi2_reservation_release(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev;  	struct se_session *sess = cmd->se_sess;  	struct se_portal_group *tpg; -	int ret = 0, rc; +	int rc;  	if (!sess || !sess->se_tpg)  		goto out;  	rc = target_check_scsi2_reservation_conflict(cmd);  	if (rc == 1)  		goto out; -	else if (rc < 0) { -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		ret = -EINVAL; -		goto out; -	} +	if (rc < 0) +		return TCM_RESERVATION_CONFLICT; -	ret = 0;  	spin_lock(&dev->dev_reservation_lock);  	if (!dev->dev_reserved_node_acl || !sess)  		goto out_unlock; @@ -223,10 +198,10 @@ int target_scsi2_reservation_release(struct se_cmd *cmd)  		goto out_unlock;  	dev->dev_reserved_node_acl = NULL; -	dev->dev_flags &= ~DF_SPC2_RESERVATIONS; -	if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { +	dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS; +	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS_WITH_ISID) {  		dev->dev_res_bin_isid = 0; -		dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; +		dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS_WITH_ISID;  	}  	tpg = sess->se_tpg;  	pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" @@ -237,25 +212,24 @@ int target_scsi2_reservation_release(struct se_cmd *cmd)  out_unlock:  	spin_unlock(&dev->dev_reservation_lock);  out: -	if (!ret) -		target_complete_cmd(cmd, GOOD); -	return ret; +	target_complete_cmd(cmd, GOOD); +	return 0;  } -int target_scsi2_reservation_reserve(struct se_cmd *cmd) +sense_reason_t +target_scsi2_reservation_reserve(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev;  	struct se_session *sess = cmd->se_sess;  	struct se_portal_group *tpg; -	int ret = 0, rc; +	sense_reason_t ret = 0; +	int rc;  	if ((cmd->t_task_cdb[1] & 0x01) &&  	    (cmd->t_task_cdb[1] & 0x02)) {  		pr_err("LongIO and Obselete Bits set, returning"  				" ILLEGAL_REQUEST\n"); -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -		ret = -EINVAL; -		goto out; +		return TCM_UNSUPPORTED_SCSI_OPCODE;  	}  	/*  	 * This is currently the case for target_core_mod passthrough struct se_cmd @@ -266,13 +240,10 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)  	rc = target_check_scsi2_reservation_conflict(cmd);  	if (rc == 1)  		goto out; -	else if (rc < 0) { -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		ret = -EINVAL; -		goto out; -	} -	ret = 0; +	if (rc < 0) +		return TCM_RESERVATION_CONFLICT; +  	tpg = sess->se_tpg;  	spin_lock(&dev->dev_reservation_lock);  	if (dev->dev_reserved_node_acl && @@ -286,16 +257,15 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)  			" from %s \n", cmd->se_lun->unpacked_lun,  			cmd->se_deve->mapped_lun,  			sess->se_node_acl->initiatorname); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		ret = -EINVAL; +		ret = TCM_RESERVATION_CONFLICT;  		goto out_unlock;  	}  	dev->dev_reserved_node_acl = sess->se_node_acl; -	dev->dev_flags |= DF_SPC2_RESERVATIONS; +	dev->dev_reservation_flags |= DRF_SPC2_RESERVATIONS;  	if (sess->sess_bin_isid != 0) {  		dev->dev_res_bin_isid = sess->sess_bin_isid; -		dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; +		dev->dev_reservation_flags |= DRF_SPC2_RESERVATIONS_WITH_ISID;  	}  	pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u"  		" for %s\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -319,9 +289,9 @@ out:   */  static int core_scsi3_pr_seq_non_holder(  	struct se_cmd *cmd, -	unsigned char *cdb,  	u32 pr_reg_type)  { +	unsigned char *cdb = cmd->t_task_cdb;  	struct se_dev_entry *se_deve;  	struct se_session *se_sess = cmd->se_sess;  	int other_cdb = 0, ignore_reg; @@ -330,17 +300,11 @@ static int core_scsi3_pr_seq_non_holder(  	int we = 0; /* Write Exclusive */  	int legacy = 0; /* Act like a legacy device and return  			 * RESERVATION CONFLICT on some CDBs */ -	/* -	 * A legacy SPC-2 reservation is being held. -	 */ -	if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) -		return core_scsi2_reservation_seq_non_holder(cmd, -					cdb, pr_reg_type);  	se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun];  	/*  	 * Determine if the registration should be ignored due to -	 * non-matching ISIDs in core_scsi3_pr_reservation_check(). +	 * non-matching ISIDs in target_scsi3_pr_reservation_check().  	 */  	ignore_reg = (pr_reg_type & 0x80000000);  	if (ignore_reg) @@ -563,10 +527,41 @@ static int core_scsi3_pr_seq_non_holder(  	return 1; /* Conflict by default */  } +static sense_reason_t +target_scsi3_pr_reservation_check(struct se_cmd *cmd) +{ +	struct se_device *dev = cmd->se_dev; +	struct se_session *sess = cmd->se_sess; +	u32 pr_reg_type; + +	if (!dev->dev_pr_res_holder) +		return 0; + +	pr_reg_type = dev->dev_pr_res_holder->pr_res_type; +	cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; +	if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) +		goto check_nonholder; + +	if (dev->dev_pr_res_holder->isid_present_at_reg) { +		if (dev->dev_pr_res_holder->pr_reg_bin_isid != +		    sess->sess_bin_isid) { +			pr_reg_type |= 0x80000000; +			goto check_nonholder; +		} +	} + +	return 0; + +check_nonholder: +	if (core_scsi3_pr_seq_non_holder(cmd, pr_reg_type)) +		return TCM_RESERVATION_CONFLICT; +	return 0; +} +  static u32 core_scsi3_pr_generation(struct se_device *dev)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	u32 prg; +  	/*  	 * PRGeneration field shall contain the value of a 32-bit wrapping  	 * counter mainted by the device server. @@ -577,56 +572,12 @@ static u32 core_scsi3_pr_generation(struct se_device *dev)  	 * See spc4r17 section 6.3.12 READ_KEYS service action  	 */  	spin_lock(&dev->dev_reservation_lock); -	prg = su_dev->t10_pr.pr_generation++; +	prg = dev->t10_pr.pr_generation++;  	spin_unlock(&dev->dev_reservation_lock);  	return prg;  } -static int core_scsi3_pr_reservation_check( -	struct se_cmd *cmd, -	u32 *pr_reg_type) -{ -	struct se_device *dev = cmd->se_dev; -	struct se_session *sess = cmd->se_sess; -	int ret; - -	if (!sess) -		return 0; -	/* -	 * A legacy SPC-2 reservation is being held. -	 */ -	if (dev->dev_flags & DF_SPC2_RESERVATIONS) -		return core_scsi2_reservation_check(cmd, pr_reg_type); - -	spin_lock(&dev->dev_reservation_lock); -	if (!dev->dev_pr_res_holder) { -		spin_unlock(&dev->dev_reservation_lock); -		return 0; -	} -	*pr_reg_type = dev->dev_pr_res_holder->pr_res_type; -	cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; -	if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) { -		spin_unlock(&dev->dev_reservation_lock); -		return -EINVAL; -	} -	if (!dev->dev_pr_res_holder->isid_present_at_reg) { -		spin_unlock(&dev->dev_reservation_lock); -		return 0; -	} -	ret = (dev->dev_pr_res_holder->pr_reg_bin_isid == -	       sess->sess_bin_isid) ? 0 : -EINVAL; -	/* -	 * Use bit in *pr_reg_type to notify ISID mismatch in -	 * core_scsi3_pr_seq_non_holder(). -	 */ -	if (ret != 0) -		*pr_reg_type |= 0x80000000; -	spin_unlock(&dev->dev_reservation_lock); - -	return ret; -} -  static struct t10_pr_registration *__core_scsi3_do_alloc_registration(  	struct se_device *dev,  	struct se_node_acl *nacl, @@ -636,7 +587,6 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(  	int all_tg_pt,  	int aptpl)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	struct t10_pr_registration *pr_reg;  	pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC); @@ -645,7 +595,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(  		return NULL;  	} -	pr_reg->pr_aptpl_buf = kzalloc(su_dev->t10_pr.pr_aptpl_buf_len, +	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"); @@ -929,7 +879,7 @@ static int __core_scsi3_check_aptpl_registration(  	struct se_dev_entry *deve)  {  	struct t10_pr_registration *pr_reg, *pr_reg_tmp; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	unsigned char i_port[PR_APTPL_MAX_IPORT_LEN];  	unsigned char t_port[PR_APTPL_MAX_TPORT_LEN];  	u16 tpgt; @@ -996,11 +946,10 @@ int core_scsi3_check_aptpl_registration(  	struct se_lun *lun,  	struct se_lun_acl *lun_acl)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	struct se_node_acl *nacl = lun_acl->se_lun_nacl;  	struct se_dev_entry *deve = nacl->device_list[lun_acl->mapped_lun]; -	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) +	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)  		return 0;  	return __core_scsi3_check_aptpl_registration(dev, tpg, lun, @@ -1051,10 +1000,9 @@ static void __core_scsi3_add_registration(  	int register_type,  	int register_move)  { -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;  	struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	/*  	 * Increment PRgeneration counter for struct se_device upon a successful @@ -1066,7 +1014,7 @@ static void __core_scsi3_add_registration(  	 * for the REGISTER.  	 */  	pr_reg->pr_res_generation = (register_move) ? -			su_dev->t10_pr.pr_generation++ : +			dev->t10_pr.pr_generation++ :  			core_scsi3_pr_generation(dev);  	spin_lock(&pr_tmpl->registration_lock); @@ -1135,7 +1083,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg(  	struct se_node_acl *nacl,  	unsigned char *isid)  { -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	struct t10_pr_registration *pr_reg, *pr_reg_tmp;  	struct se_portal_group *tpg; @@ -1160,7 +1108,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg(  			 * for fabric modules (iSCSI) requiring them.  			 */  			if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) { -				if (dev->se_sub_dev->se_dev_attrib.enforce_pr_isids) +				if (dev->dev_attrib.enforce_pr_isids)  					continue;  			}  			atomic_inc(&pr_reg->pr_res_holders); @@ -1274,7 +1222,7 @@ static void __core_scsi3_free_registration(  {  	struct target_core_fabric_ops *tfo =  			pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	char i_buf[PR_REG_ISID_ID_LEN];  	int prf_isid; @@ -1335,7 +1283,7 @@ void core_scsi3_free_pr_reg_from_nacl(  	struct se_device *dev,  	struct se_node_acl *nacl)  { -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;  	/*  	 * If the passed se_node_acl matches the reservation holder, @@ -1365,7 +1313,7 @@ void core_scsi3_free_pr_reg_from_nacl(  void core_scsi3_free_all_registrations(  	struct se_device *dev)  { -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;  	spin_lock(&dev->dev_reservation_lock); @@ -1479,7 +1427,8 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)  	smp_mb__after_atomic_dec();  } -static int core_scsi3_decode_spec_i_port( +static sense_reason_t +core_scsi3_decode_spec_i_port(  	struct se_cmd *cmd,  	struct se_portal_group *tpg,  	unsigned char *l_isid, @@ -1501,8 +1450,9 @@ static int core_scsi3_decode_spec_i_port(  	unsigned char *buf;  	unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;  	char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; +	sense_reason_t ret;  	u32 tpdl, tid_len = 0; -	int ret, dest_local_nexus, prf_isid; +	int dest_local_nexus, prf_isid;  	u32 dest_rtpi = 0;  	memset(dest_iport, 0, 64); @@ -1517,8 +1467,7 @@ static int core_scsi3_decode_spec_i_port(  	tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL);  	if (!tidh_new) {  		pr_err("Unable to allocate tidh_new\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	INIT_LIST_HEAD(&tidh_new->dest_list);  	tidh_new->dest_tpg = tpg; @@ -1530,8 +1479,7 @@ static int core_scsi3_decode_spec_i_port(  				sa_res_key, all_tg_pt, aptpl);  	if (!local_pr_reg) {  		kfree(tidh_new); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -ENOMEM; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	tidh_new->dest_pr_reg = local_pr_reg;  	/* @@ -1545,12 +1493,16 @@ static int core_scsi3_decode_spec_i_port(  	if (cmd->data_length < 28) {  		pr_warn("SPC-PR: Received PR OUT parameter list"  			" length too small: %u\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) { +		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		goto out; +	} +  	/*  	 * For a PERSISTENT RESERVE OUT specify initiator ports payload,  	 * first extract TransportID Parameter Data Length, and make sure @@ -1565,9 +1517,8 @@ static int core_scsi3_decode_spec_i_port(  		pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header"  			" does not equal CDB data_length: %u\n", tpdl,  			cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; -		goto out; +		ret = TCM_INVALID_PARAMETER_LIST; +		goto out_unmap;  	}  	/*  	 * Start processing the received transport IDs using the @@ -1610,16 +1561,13 @@ static int core_scsi3_decode_spec_i_port(  			smp_mb__after_atomic_inc();  			spin_unlock(&dev->se_port_lock); -			ret = core_scsi3_tpg_depend_item(tmp_tpg); -			if (ret != 0) { +			if (core_scsi3_tpg_depend_item(tmp_tpg)) {  				pr_err(" core_scsi3_tpg_depend_item()"  					" for tmp_tpg\n");  				atomic_dec(&tmp_tpg->tpg_pr_ref_count);  				smp_mb__after_atomic_dec(); -				cmd->scsi_sense_reason = -					TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -				ret = -EINVAL; -				goto out; +				ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +				goto out_unmap;  			}  			/*  			 * Locate the destination initiator ACL to be registered @@ -1641,17 +1589,14 @@ static int core_scsi3_decode_spec_i_port(  				continue;  			} -			ret = core_scsi3_nodeacl_depend_item(dest_node_acl); -			if (ret != 0) { +			if (core_scsi3_nodeacl_depend_item(dest_node_acl)) {  				pr_err("configfs_depend_item() failed"  					" for dest_node_acl->acl_group\n");  				atomic_dec(&dest_node_acl->acl_pr_ref_count);  				smp_mb__after_atomic_dec();  				core_scsi3_tpg_undepend_item(tmp_tpg); -				cmd->scsi_sense_reason = -					TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -				ret = -EINVAL; -				goto out; +				ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +				goto out_unmap;  			}  			dest_tpg = tmp_tpg; @@ -1668,9 +1613,8 @@ static int core_scsi3_decode_spec_i_port(  		if (!dest_tpg) {  			pr_err("SPC-3 PR SPEC_I_PT: Unable to locate"  					" dest_tpg\n"); -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			ret = -EINVAL; -			goto out; +			ret = TCM_INVALID_PARAMETER_LIST; +			goto out_unmap;  		}  		pr_debug("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u" @@ -1683,9 +1627,8 @@ static int core_scsi3_decode_spec_i_port(  				" %u for Transport ID: %s\n", tid_len, ptr);  			core_scsi3_nodeacl_undepend_item(dest_node_acl);  			core_scsi3_tpg_undepend_item(dest_tpg); -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			ret = -EINVAL; -			goto out; +			ret = TCM_INVALID_PARAMETER_LIST; +			goto out_unmap;  		}  		/*  		 * Locate the desintation struct se_dev_entry pointer for matching @@ -1702,23 +1645,19 @@ static int core_scsi3_decode_spec_i_port(  			core_scsi3_nodeacl_undepend_item(dest_node_acl);  			core_scsi3_tpg_undepend_item(dest_tpg); -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			ret = -EINVAL; -			goto out; +			ret = TCM_INVALID_PARAMETER_LIST; +			goto out_unmap;  		} -		ret = core_scsi3_lunacl_depend_item(dest_se_deve); -		if (ret < 0) { +		if (core_scsi3_lunacl_depend_item(dest_se_deve)) {  			pr_err("core_scsi3_lunacl_depend_item()"  					" failed\n");  			atomic_dec(&dest_se_deve->pr_ref_count);  			smp_mb__after_atomic_dec();  			core_scsi3_nodeacl_undepend_item(dest_node_acl);  			core_scsi3_tpg_undepend_item(dest_tpg); -			cmd->scsi_sense_reason = -				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -			ret = -EINVAL; -			goto out; +			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +			goto out_unmap;  		}  		pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" @@ -1754,10 +1693,8 @@ static int core_scsi3_decode_spec_i_port(  			core_scsi3_lunacl_undepend_item(dest_se_deve);  			core_scsi3_nodeacl_undepend_item(dest_node_acl);  			core_scsi3_tpg_undepend_item(dest_tpg); -			cmd->scsi_sense_reason = -				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -			ret = -ENOMEM; -			goto out; +			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +			goto out_unmap;  		}  		INIT_LIST_HEAD(&tidh_new->dest_list);  		tidh_new->dest_tpg = dest_tpg; @@ -1788,9 +1725,8 @@ static int core_scsi3_decode_spec_i_port(  			core_scsi3_nodeacl_undepend_item(dest_node_acl);  			core_scsi3_tpg_undepend_item(dest_tpg);  			kfree(tidh_new); -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			ret = -EINVAL; -			goto out; +			ret = TCM_INVALID_PARAMETER_LIST; +			goto out_unmap;  		}  		tidh_new->dest_pr_reg = dest_pr_reg;  		list_add_tail(&tidh_new->dest_list, &tid_dest_list); @@ -1848,8 +1784,9 @@ static int core_scsi3_decode_spec_i_port(  	}  	return 0; -out: +out_unmap:  	transport_kunmap_data_sg(cmd); +out:  	/*  	 * For the failure case, release everything from tid_dest_list  	 * including *dest_pr_reg and the configfs dependances.. @@ -1899,7 +1836,6 @@ static int __core_scsi3_update_aptpl_buf(  {  	struct se_lun *lun;  	struct se_portal_group *tpg; -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	struct t10_pr_registration *pr_reg;  	unsigned char tmp[512], isid_buf[32];  	ssize_t len = 0; @@ -1917,8 +1853,8 @@ static int __core_scsi3_update_aptpl_buf(  	/*  	 * Walk the registration list..  	 */ -	spin_lock(&su_dev->t10_pr.registration_lock); -	list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, +	spin_lock(&dev->t10_pr.registration_lock); +	list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,  			pr_reg_list) {  		tmp[0] = '\0'; @@ -1963,7 +1899,7 @@ 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(&su_dev->t10_pr.registration_lock); +			spin_unlock(&dev->t10_pr.registration_lock);  			return -EMSGSIZE;  		}  		len += sprintf(buf+len, "%s", tmp); @@ -1981,13 +1917,13 @@ 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(&su_dev->t10_pr.registration_lock); +			spin_unlock(&dev->t10_pr.registration_lock);  			return -EMSGSIZE;  		}  		len += sprintf(buf+len, "%s", tmp);  		reg_count++;  	} -	spin_unlock(&su_dev->t10_pr.registration_lock); +	spin_unlock(&dev->t10_pr.registration_lock);  	if (!reg_count)  		len += sprintf(buf+len, "No Registrations or Reservations"); @@ -2019,7 +1955,7 @@ static int __core_scsi3_write_aptpl_to_file(  	unsigned char *buf,  	u32 pr_aptpl_buf_len)  { -	struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; +	struct t10_wwn *wwn = &dev->t10_wwn;  	struct file *file;  	struct iovec iov[1];  	mm_segment_t old_fs; @@ -2065,14 +2001,15 @@ static int __core_scsi3_write_aptpl_to_file(  	return 0;  } -static int core_scsi3_update_and_write_aptpl( -	struct se_device *dev, -	unsigned char *in_buf, -	u32 in_pr_aptpl_buf_len) +static int +core_scsi3_update_and_write_aptpl(struct se_device *dev, unsigned char *in_buf, +		u32 in_pr_aptpl_buf_len)  {  	unsigned char null_buf[64], *buf;  	u32 pr_aptpl_buf_len; -	int ret, clear_aptpl_metadata = 0; +	int clear_aptpl_metadata = 0; +	int ret; +  	/*  	 * Can be called with a NULL pointer from PROUT service action CLEAR  	 */ @@ -2094,25 +2031,17 @@ static int core_scsi3_update_and_write_aptpl(  				clear_aptpl_metadata);  	if (ret != 0)  		return ret; +  	/*  	 * __core_scsi3_write_aptpl_to_file() will call strlen()  	 * on the passed buf to determine pr_aptpl_buf_len.  	 */ -	ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0); -	if (ret != 0) -		return ret; - -	return ret; +	return __core_scsi3_write_aptpl_to_file(dev, buf, 0);  } -static int 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) +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)  {  	struct se_session *se_sess = cmd->se_sess;  	struct se_device *dev = cmd->se_dev; @@ -2120,16 +2049,16 @@ static int core_scsi3_emulate_pro_register(  	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_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	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; -	int pr_holder = 0, ret = 0, type; +	sense_reason_t ret; +	int pr_holder = 0, type;  	if (!se_sess || !se_lun) {  		pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	se_tpg = se_sess->se_tpg;  	se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; @@ -2148,8 +2077,7 @@ static int core_scsi3_emulate_pro_register(  		if (res_key) {  			pr_warn("SPC-3 PR: Reservation Key non-zero"  				" for SA REGISTER, returning CONFLICT\n"); -			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -			return -EINVAL; +			return TCM_RESERVATION_CONFLICT;  		}  		/*  		 * Do nothing but return GOOD status. @@ -2163,15 +2091,13 @@ static int core_scsi3_emulate_pro_register(  			 * Port Endpoint that the PRO was received from on the  			 * Logical Unit of the SCSI device server.  			 */ -			ret = core_scsi3_alloc_registration(cmd->se_dev, +			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); -			if (ret != 0) { +					ignore_key, 0)) {  				pr_err("Unable to allocate"  					" struct t10_pr_registration\n"); -				cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -				return -EINVAL; +				return TCM_INVALID_PARAMETER_LIST;  			}  		} else {  			/* @@ -2205,201 +2131,192 @@ static int core_scsi3_emulate_pro_register(  		pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev,  				se_sess->se_node_acl, se_sess); -		ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, +		if (core_scsi3_update_and_write_aptpl(cmd->se_dev,  				&pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len); -		if (!ret) { +				pr_tmpl->pr_aptpl_buf_len)) {  			pr_tmpl->pr_aptpl_active = 1;  			pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n");  		} -		core_scsi3_put_pr_reg(pr_reg); -		return ret; -	} else { -		/* -		 * 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); -				core_scsi3_put_pr_reg(pr_reg); -				cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -				return -EINVAL; -			} +		goto out_put_pr_reg; +	} + +	/* +	 * 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;  		} -		if (spec_i_pt) { -			pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" -				" set while sa_res_key=0\n"); -			core_scsi3_put_pr_reg(pr_reg); -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			return -EINVAL; +	} + +	if (spec_i_pt) { +		pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" +			" set while sa_res_key=0\n"); +		ret = TCM_INVALID_PARAMETER_LIST; +		goto out_put_pr_reg; +	} + +	/* +	 * 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" +			" registration exists, but ALL_TG_PT=1 bit not" +			" present in received PROUT\n"); +		ret = TCM_INVALID_CDB_FIELD; +		goto out_put_pr_reg; +	} + +	/* +	 * Allocate APTPL metadata buffer used for UNREGISTER ops +	 */ +	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;  		} -		/* -		 * 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" -				" registration exists, but ALL_TG_PT=1 bit not" -				" present in received PROUT\n"); -			core_scsi3_put_pr_reg(pr_reg); -			cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -			return -EINVAL; +	} + +	/* +	 * 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) { +		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;  		} + +		spin_lock(&pr_tmpl->registration_lock);  		/* -		 * Allocate APTPL metadata buffer used for UNREGISTER ops +		 * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port +		 * and matching pr_res_key.  		 */ -		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"); -				core_scsi3_put_pr_reg(pr_reg); -				cmd->scsi_sense_reason = -					TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -				return -EINVAL; +		if (pr_reg->pr_reg_all_tg_pt) { +			list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, +					&pr_tmpl->registration_list, +					pr_reg_list) { + +				if (!pr_reg_p->pr_reg_all_tg_pt) +					continue; +				if (pr_reg_p->pr_res_key != res_key) +					continue; +				if (pr_reg == pr_reg_p) +					continue; +				if (strcmp(pr_reg->pr_reg_nacl->initiatorname, +					   pr_reg_p->pr_reg_nacl->initiatorname)) +					continue; + +				__core_scsi3_free_registration(dev, +						pr_reg_p, NULL, 0);  			}  		} +  		/* -		 * sa_res_key=0 Unregister Reservation Key for registered I_T -		 * Nexus sa_res_key=1 Change Reservation Key for registered I_T -		 * Nexus. +		 * Release the calling I_T Nexus registration now..  		 */ -		if (!sa_res_key) { -			pr_holder = core_scsi3_check_implict_release( -					cmd->se_dev, pr_reg); -			if (pr_holder < 0) { -				kfree(pr_aptpl_buf); -				core_scsi3_put_pr_reg(pr_reg); -				cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -				return -EINVAL; -			} - -			spin_lock(&pr_tmpl->registration_lock); -			/* -			 * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port -			 * and matching pr_res_key. -			 */ -			if (pr_reg->pr_reg_all_tg_pt) { -				list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, -						&pr_tmpl->registration_list, -						pr_reg_list) { - -					if (!pr_reg_p->pr_reg_all_tg_pt) -						continue; +		__core_scsi3_free_registration(cmd->se_dev, pr_reg, NULL, 1); -					if (pr_reg_p->pr_res_key != res_key) -						continue; - -					if (pr_reg == pr_reg_p) -						continue; - -					if (strcmp(pr_reg->pr_reg_nacl->initiatorname, -						   pr_reg_p->pr_reg_nacl->initiatorname)) -						continue; - -					__core_scsi3_free_registration(dev, -							pr_reg_p, NULL, 0); -				} -			} -			/* -			 * Release the calling I_T Nexus registration now.. -			 */ -			__core_scsi3_free_registration(cmd->se_dev, pr_reg, -							NULL, 1); -			/* -			 * From spc4r17, section 5.7.11.3 Unregistering -			 * -			 * If the persistent reservation is a registrants only -			 * type, the device server shall establish a unit -			 * attention condition for the initiator port associated -			 * with every registered I_T nexus except for the I_T -			 * nexus on which the PERSISTENT RESERVE OUT command was -			 * received, with the additional sense code set to -			 * RESERVATIONS RELEASED. -			 */ -			if (pr_holder && -			   ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || -			    (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) { -				list_for_each_entry(pr_reg_p, -						&pr_tmpl->registration_list, -						pr_reg_list) { - -					core_scsi3_ua_allocate( -						pr_reg_p->pr_reg_nacl, -						pr_reg_p->pr_res_mapped_lun, -						0x2A, -						ASCQ_2AH_RESERVATIONS_RELEASED); -				} +		/* +		 * From spc4r17, section 5.7.11.3 Unregistering +		 * +		 * If the persistent reservation is a registrants only +		 * type, the device server shall establish a unit +		 * attention condition for the initiator port associated +		 * with every registered I_T nexus except for the I_T +		 * nexus on which the PERSISTENT RESERVE OUT command was +		 * received, with the additional sense code set to +		 * RESERVATIONS RELEASED. +		 */ +		if (pr_holder && +		   (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || +		    type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { +			list_for_each_entry(pr_reg_p, +					&pr_tmpl->registration_list, +					pr_reg_list) { + +				core_scsi3_ua_allocate( +					pr_reg_p->pr_reg_nacl, +					pr_reg_p->pr_res_mapped_lun, +					0x2A, +					ASCQ_2AH_RESERVATIONS_RELEASED);  			} -			spin_unlock(&pr_tmpl->registration_lock); +		} +		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 (!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; +		} -			ret = core_scsi3_update_and_write_aptpl(dev, -					&pr_aptpl_buf[0], -					pr_tmpl->pr_aptpl_buf_len); -			if (!ret) { -				pr_tmpl->pr_aptpl_active = 1; -				pr_debug("SPC-3 PR: Set APTPL Bit Activated" -						" for UNREGISTER\n"); -			} +		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"); +		} -			kfree(pr_aptpl_buf); -			return ret; -		} else { -			/* -			 * 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); -				core_scsi3_put_pr_reg(pr_reg); -				pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" -						" for REGISTER\n"); -				return 0; -			} +		goto out_free_aptpl_buf; +	} -			ret = core_scsi3_update_and_write_aptpl(dev, -					&pr_aptpl_buf[0], -					pr_tmpl->pr_aptpl_buf_len); -			if (!ret) { -				pr_tmpl->pr_aptpl_active = 1; -				pr_debug("SPC-3 PR: Set APTPL Bit Activated" -						" for REGISTER\n"); -			} +	/* +	 * 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); -			kfree(pr_aptpl_buf); -			core_scsi3_put_pr_reg(pr_reg); -		} +	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;  	} -	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 REGISTER\n"); +	} + +out_free_aptpl_buf: +	kfree(pr_aptpl_buf); +	ret = 0; +out_put_pr_reg: +	core_scsi3_put_pr_reg(pr_reg); +	return ret;  }  unsigned char *core_scsi3_pr_dump_type(int type) @@ -2424,26 +2341,23 @@ unsigned char *core_scsi3_pr_dump_type(int type)  	return "Unknown SPC-3 PR Type";  } -static int core_scsi3_pro_reserve( -	struct se_cmd *cmd, -	struct se_device *dev, -	int type, -	int scope, -	u64 res_key) +static sense_reason_t +core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)  { +	struct se_device *dev = cmd->se_dev;  	struct se_session *se_sess = cmd->se_sess;  	struct se_lun *se_lun = cmd->se_lun;  	struct t10_pr_registration *pr_reg, *pr_res_holder; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	char i_buf[PR_REG_ISID_ID_LEN]; -	int ret, prf_isid; +	sense_reason_t ret; +	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN);  	if (!se_sess || !se_lun) {  		pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	/*  	 * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2453,8 +2367,7 @@ static int core_scsi3_pro_reserve(  	if (!pr_reg) {  		pr_err("SPC-3 PR: Unable to locate"  			" PR_REGISTERED *pr_reg for RESERVE\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	/*  	 * From spc4r17 Section 5.7.9: Reserving: @@ -2469,9 +2382,8 @@ static int core_scsi3_pro_reserve(  		pr_err("SPC-3 PR RESERVE: Received res_key: 0x%016Lx"  			" does not match existing SA REGISTER res_key:"  			" 0x%016Lx\n", res_key, pr_reg->pr_res_key); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		ret = TCM_RESERVATION_CONFLICT; +		goto out_put_pr_reg;  	}  	/*  	 * From spc4r17 Section 5.7.9: Reserving: @@ -2485,9 +2397,8 @@ static int core_scsi3_pro_reserve(  	 */  	if (scope != PR_SCOPE_LU_SCOPE) {  		pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST; +		goto out_put_pr_reg;  	}  	/*  	 * See if we have an existing PR reservation holder pointer at @@ -2518,9 +2429,8 @@ static int core_scsi3_pro_reserve(  				pr_res_holder->pr_reg_nacl->initiatorname);  			spin_unlock(&dev->dev_reservation_lock); -			core_scsi3_put_pr_reg(pr_reg); -			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -			return -EINVAL; +			ret = TCM_RESERVATION_CONFLICT; +			goto out_put_pr_reg;  		}  		/*  		 * From spc4r17 Section 5.7.9: Reserving: @@ -2542,9 +2452,8 @@ static int core_scsi3_pro_reserve(  				pr_res_holder->pr_reg_nacl->initiatorname);  			spin_unlock(&dev->dev_reservation_lock); -			core_scsi3_put_pr_reg(pr_reg); -			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -			return -EINVAL; +			ret = TCM_RESERVATION_CONFLICT; +			goto out_put_pr_reg;  		}  		/*  		 * From spc4r17 Section 5.7.9: Reserving: @@ -2557,8 +2466,8 @@ static int core_scsi3_pro_reserve(  		 * shall completethe command with GOOD status.  		 */  		spin_unlock(&dev->dev_reservation_lock); -		core_scsi3_put_pr_reg(pr_reg); -		return 0; +		ret = 0; +		goto out_put_pr_reg;  	}  	/*  	 * Otherwise, our *pr_reg becomes the PR reservation holder for said @@ -2582,27 +2491,24 @@ static int core_scsi3_pro_reserve(  	spin_unlock(&dev->dev_reservation_lock);  	if (pr_tmpl->pr_aptpl_active) { -		ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, +		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,  				&pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len); -		if (!ret) +				pr_tmpl->pr_aptpl_buf_len)) {  			pr_debug("SPC-3 PR: Updated APTPL metadata"  					" for RESERVE\n"); +		}  	} +	ret = 0; +out_put_pr_reg:  	core_scsi3_put_pr_reg(pr_reg); -	return 0; +	return ret;  } -static int core_scsi3_emulate_pro_reserve( -	struct se_cmd *cmd, -	int type, -	int scope, -	u64 res_key) +static sense_reason_t +core_scsi3_emulate_pro_reserve(struct se_cmd *cmd, int type, int scope, +		u64 res_key)  { -	struct se_device *dev = cmd->se_dev; -	int ret = 0; -  	switch (type) {  	case PR_TYPE_WRITE_EXCLUSIVE:  	case PR_TYPE_EXCLUSIVE_ACCESS: @@ -2610,16 +2516,12 @@ static int core_scsi3_emulate_pro_reserve(  	case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:  	case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:  	case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: -		ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key); -		break; +		return core_scsi3_pro_reserve(cmd, type, scope, res_key);  	default:  		pr_err("SPC-3 PR: Unknown Service Action RESERVE Type:"  			" 0x%02x\n", type); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	} - -	return ret;  }  /* @@ -2657,23 +2559,21 @@ static void __core_scsi3_complete_pro_release(  	pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0;  } -static int core_scsi3_emulate_pro_release( -	struct se_cmd *cmd, -	int type, -	int scope, -	u64 res_key) +static sense_reason_t +core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope, +		u64 res_key)  {  	struct se_device *dev = cmd->se_dev;  	struct se_session *se_sess = cmd->se_sess;  	struct se_lun *se_lun = cmd->se_lun;  	struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; -	int ret, all_reg = 0; +	struct t10_reservation *pr_tmpl = &dev->t10_pr; +	int all_reg = 0; +	sense_reason_t ret = 0;  	if (!se_sess || !se_lun) {  		pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	/*  	 * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2682,8 +2582,7 @@ static int core_scsi3_emulate_pro_release(  	if (!pr_reg) {  		pr_err("SPC-3 PR: Unable to locate"  			" PR_REGISTERED *pr_reg for RELEASE\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	/*  	 * From spc4r17 Section 5.7.11.2 Releasing: @@ -2704,8 +2603,7 @@ static int core_scsi3_emulate_pro_release(  		 * No persistent reservation, return GOOD status.  		 */  		spin_unlock(&dev->dev_reservation_lock); -		core_scsi3_put_pr_reg(pr_reg); -		return 0; +		goto out_put_pr_reg;  	}  	if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||  	    (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) @@ -2718,9 +2616,9 @@ static int core_scsi3_emulate_pro_release(  		 * persistent reservation holder. return GOOD status.  		 */  		spin_unlock(&dev->dev_reservation_lock); -		core_scsi3_put_pr_reg(pr_reg); -		return 0; +		goto out_put_pr_reg;  	} +  	/*  	 * From spc4r17 Section 5.7.11.2 Releasing:  	 * @@ -2740,9 +2638,8 @@ static int core_scsi3_emulate_pro_release(  			" does not match existing SA REGISTER res_key:"  			" 0x%016Lx\n", res_key, pr_reg->pr_res_key);  		spin_unlock(&dev->dev_reservation_lock); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		ret = TCM_RESERVATION_CONFLICT; +		goto out_put_pr_reg;  	}  	/*  	 * From spc4r17 Section 5.7.11.2 Releasing and above: @@ -2763,9 +2660,8 @@ static int core_scsi3_emulate_pro_release(  			pr_res_holder->pr_reg_nacl->initiatorname);  		spin_unlock(&dev->dev_reservation_lock); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		ret = TCM_RESERVATION_CONFLICT; +		goto out_put_pr_reg;  	}  	/*  	 * In response to a persistent reservation release request from the @@ -2818,25 +2714,23 @@ static int core_scsi3_emulate_pro_release(  write_aptpl:  	if (pr_tmpl->pr_aptpl_active) { -		ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, -				&pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len); -		if (!ret) +		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"); +		}  	} - +out_put_pr_reg:  	core_scsi3_put_pr_reg(pr_reg); -	return 0; +	return ret;  } -static int core_scsi3_emulate_pro_clear( -	struct se_cmd *cmd, -	u64 res_key) +static sense_reason_t +core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key)  {  	struct se_device *dev = cmd->se_dev;  	struct se_node_acl *pr_reg_nacl;  	struct se_session *se_sess = cmd->se_sess; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;  	u32 pr_res_mapped_lun = 0;  	int calling_it_nexus = 0; @@ -2848,8 +2742,7 @@ static int core_scsi3_emulate_pro_clear(  	if (!pr_reg_n) {  		pr_err("SPC-3 PR: Unable to locate"  			" PR_REGISTERED *pr_reg for CLEAR\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	/*  	 * From spc4r17 section 5.7.11.6, Clearing: @@ -2868,8 +2761,7 @@ static int core_scsi3_emulate_pro_clear(  			" existing SA REGISTER res_key:"  			" 0x%016Lx\n", res_key, pr_reg_n->pr_res_key);  		core_scsi3_put_pr_reg(pr_reg_n); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		return TCM_RESERVATION_CONFLICT;  	}  	/*  	 * a) Release the persistent reservation, if any; @@ -2993,28 +2885,22 @@ static void core_scsi3_release_preempt_and_abort(  	}  } -static int core_scsi3_pro_preempt( -	struct se_cmd *cmd, -	int type, -	int scope, -	u64 res_key, -	u64 sa_res_key, -	int abort) +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)  {  	struct se_device *dev = cmd->se_dev;  	struct se_node_acl *pr_reg_nacl;  	struct se_session *se_sess = cmd->se_sess;  	LIST_HEAD(preempt_and_abort_list);  	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	u32 pr_res_mapped_lun = 0;  	int all_reg = 0, calling_it_nexus = 0, released_regs = 0; -	int prh_type = 0, prh_scope = 0, ret; +	int prh_type = 0, prh_scope = 0; -	if (!se_sess) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; -	} +	if (!se_sess) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,  				se_sess); @@ -3022,19 +2908,16 @@ static int core_scsi3_pro_preempt(  		pr_err("SPC-3 PR: Unable to locate"  			" PR_REGISTERED *pr_reg for PREEMPT%s\n",  			(abort) ? "_AND_ABORT" : ""); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		return TCM_RESERVATION_CONFLICT;  	}  	if (pr_reg_n->pr_res_key != res_key) {  		core_scsi3_put_pr_reg(pr_reg_n); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		return TCM_RESERVATION_CONFLICT;  	}  	if (scope != PR_SCOPE_LU_SCOPE) {  		pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);  		core_scsi3_put_pr_reg(pr_reg_n); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		return TCM_INVALID_PARAMETER_LIST;  	}  	spin_lock(&dev->dev_reservation_lock); @@ -3047,8 +2930,7 @@ static int core_scsi3_pro_preempt(  	if (!all_reg && !sa_res_key) {  		spin_unlock(&dev->dev_reservation_lock);  		core_scsi3_put_pr_reg(pr_reg_n); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		return TCM_INVALID_PARAMETER_LIST;  	}  	/*  	 * From spc4r17, section 5.7.11.4.4 Removing Registrations: @@ -3142,8 +3024,7 @@ static int core_scsi3_pro_preempt(  		if (!released_regs) {  			spin_unlock(&dev->dev_reservation_lock);  			core_scsi3_put_pr_reg(pr_reg_n); -			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -			return -EINVAL; +			return TCM_RESERVATION_CONFLICT;  		}  		/*  		 * For an existing all registrants type reservation @@ -3162,13 +3043,13 @@ static int core_scsi3_pro_preempt(  		spin_unlock(&dev->dev_reservation_lock);  		if (pr_tmpl->pr_aptpl_active) { -			ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, +			if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,  					&pr_reg_n->pr_aptpl_buf[0], -					pr_tmpl->pr_aptpl_buf_len); -			if (!ret) +					pr_tmpl->pr_aptpl_buf_len)) {  				pr_debug("SPC-3 PR: Updated APTPL"  					" metadata for  PREEMPT%s\n", (abort) ?  					"_AND_ABORT" : ""); +			}  		}  		core_scsi3_put_pr_reg(pr_reg_n); @@ -3298,12 +3179,12 @@ static int core_scsi3_pro_preempt(  	}  	if (pr_tmpl->pr_aptpl_active) { -		ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, +		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,  				&pr_reg_n->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len); -		if (!ret) +				pr_tmpl->pr_aptpl_buf_len)) {  			pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT" -				"%s\n", (abort) ? "_AND_ABORT" : ""); +				"%s\n", abort ? "_AND_ABORT" : ""); +		}  	}  	core_scsi3_put_pr_reg(pr_reg_n); @@ -3311,16 +3192,10 @@ static int core_scsi3_pro_preempt(  	return 0;  } -static int core_scsi3_emulate_pro_preempt( -	struct se_cmd *cmd, -	int type, -	int scope, -	u64 res_key, -	u64 sa_res_key, -	int abort) +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)  { -	int ret = 0; -  	switch (type) {  	case PR_TYPE_WRITE_EXCLUSIVE:  	case PR_TYPE_EXCLUSIVE_ACCESS: @@ -3328,26 +3203,19 @@ static int core_scsi3_emulate_pro_preempt(  	case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:  	case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:  	case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: -		ret = core_scsi3_pro_preempt(cmd, type, scope, -				res_key, sa_res_key, abort); -		break; +		return core_scsi3_pro_preempt(cmd, type, scope, res_key, +					      sa_res_key, abort);  	default:  		pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s"  			" Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	} - -	return ret;  } -static int core_scsi3_emulate_pro_register_and_move( -	struct se_cmd *cmd, -	u64 res_key, -	u64 sa_res_key, -	int aptpl, -	int unreg) +static sense_reason_t +core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, +		u64 sa_res_key, int aptpl, int unreg)  {  	struct se_session *se_sess = cmd->se_sess;  	struct se_device *dev = cmd->se_dev; @@ -3358,20 +3226,21 @@ static int core_scsi3_emulate_pro_register_and_move(  	struct se_portal_group *se_tpg, *dest_se_tpg = NULL;  	struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;  	struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	unsigned char *buf;  	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, ret, matching_iname, prf_isid; +	int new_reg = 0, type, scope, matching_iname, prf_isid; +	sense_reason_t ret;  	unsigned short rtpi;  	unsigned char proto_ident;  	if (!se_sess || !se_lun) {  		pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	} +  	memset(dest_iport, 0, 64);  	memset(i_buf, 0, PR_REG_ISID_ID_LEN);  	se_tpg = se_sess->se_tpg; @@ -3387,8 +3256,7 @@ static int core_scsi3_emulate_pro_register_and_move(  	if (!pr_reg) {  		pr_err("SPC-3 PR: Unable to locate PR_REGISTERED"  			" *pr_reg for REGISTER_AND_MOVE\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	/*  	 * The provided reservation key much match the existing reservation key @@ -3398,9 +3266,8 @@ static int core_scsi3_emulate_pro_register_and_move(  		pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received"  			" res_key: 0x%016Lx does not match existing SA REGISTER"  			" res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		ret = TCM_RESERVATION_CONFLICT; +		goto out_put_pr_reg;  	}  	/*  	 * The service active reservation key needs to be non zero @@ -3408,9 +3275,8 @@ static int core_scsi3_emulate_pro_register_and_move(  	if (!sa_res_key) {  		pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received zero"  			" sa_res_key\n"); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST; +		goto out_put_pr_reg;  	}  	/* @@ -3419,6 +3285,11 @@ static int core_scsi3_emulate_pro_register_and_move(  	 * information.  	 */  	buf = transport_kmap_data_sg(cmd); +	if (!buf) { +		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		goto out_put_pr_reg; +	} +  	rtpi = (buf[18] & 0xff) << 8;  	rtpi |= buf[19] & 0xff;  	tid_len = (buf[20] & 0xff) << 24; @@ -3432,9 +3303,8 @@ static int core_scsi3_emulate_pro_register_and_move(  		pr_err("SPC-3 PR: Illegal tid_len: %u + 24 byte header"  			" does not equal CDB data_length: %u\n", tid_len,  			cmd->data_length); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST; +		goto out_put_pr_reg;  	}  	spin_lock(&dev->se_port_lock); @@ -3452,15 +3322,13 @@ static int core_scsi3_emulate_pro_register_and_move(  		smp_mb__after_atomic_inc();  		spin_unlock(&dev->se_port_lock); -		ret = core_scsi3_tpg_depend_item(dest_se_tpg); -		if (ret != 0) { +		if (core_scsi3_tpg_depend_item(dest_se_tpg)) {  			pr_err("core_scsi3_tpg_depend_item() failed"  				" for dest_se_tpg\n");  			atomic_dec(&dest_se_tpg->tpg_pr_ref_count);  			smp_mb__after_atomic_dec(); -			core_scsi3_put_pr_reg(pr_reg); -			cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -			return -EINVAL; +			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +			goto out_put_pr_reg;  		}  		spin_lock(&dev->se_port_lock); @@ -3472,12 +3340,15 @@ static int core_scsi3_emulate_pro_register_and_move(  		pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate"  			" fabric ops from Relative Target Port Identifier:"  			" %hu\n", rtpi); -		core_scsi3_put_pr_reg(pr_reg); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		return -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST; +		goto out_put_pr_reg;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) { +		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		goto out_put_pr_reg; +	}  	proto_ident = (buf[24] & 0x0f);  	pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" @@ -3489,16 +3360,14 @@ static int core_scsi3_emulate_pro_register_and_move(  			" from fabric: %s\n", proto_ident,  			dest_tf_ops->get_fabric_proto_ident(dest_se_tpg),  			dest_tf_ops->get_fabric_name()); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	}  	if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) {  		pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not"  			" containg a valid tpg_parse_pr_out_transport_id"  			" function pointer\n"); -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		ret = -EINVAL; +		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  		goto out;  	}  	initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, @@ -3506,8 +3375,7 @@ static int core_scsi3_emulate_pro_register_and_move(  	if (!initiator_str) {  		pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate"  			" initiator_str from Transport ID\n"); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	} @@ -3536,8 +3404,7 @@ static int core_scsi3_emulate_pro_register_and_move(  		pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s"  			" matches: %s on received I_T Nexus\n", initiator_str,  			pr_reg_nacl->initiatorname); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	}  	if (!strcmp(iport_ptr, pr_reg->pr_reg_isid)) { @@ -3545,8 +3412,7 @@ static int core_scsi3_emulate_pro_register_and_move(  			" matches: %s %s on received I_T Nexus\n",  			initiator_str, iport_ptr, pr_reg_nacl->initiatorname,  			pr_reg->pr_reg_isid); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	}  after_iport_check: @@ -3566,19 +3432,17 @@ after_iport_check:  		pr_err("Unable to locate %s dest_node_acl for"  			" TransportID%s\n", dest_tf_ops->get_fabric_name(),  			initiator_str); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	} -	ret = core_scsi3_nodeacl_depend_item(dest_node_acl); -	if (ret != 0) { + +	if (core_scsi3_nodeacl_depend_item(dest_node_acl)) {  		pr_err("core_scsi3_nodeacl_depend_item() for"  			" dest_node_acl\n");  		atomic_dec(&dest_node_acl->acl_pr_ref_count);  		smp_mb__after_atomic_dec();  		dest_node_acl = NULL; -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	} @@ -3594,19 +3458,16 @@ after_iport_check:  	if (!dest_se_deve) {  		pr_err("Unable to locate %s dest_se_deve from RTPI:"  			" %hu\n",  dest_tf_ops->get_fabric_name(), rtpi); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; +		ret = TCM_INVALID_PARAMETER_LIST;  		goto out;  	} -	ret = core_scsi3_lunacl_depend_item(dest_se_deve); -	if (ret < 0) { +	if (core_scsi3_lunacl_depend_item(dest_se_deve)) {  		pr_err("core_scsi3_lunacl_depend_item() failed\n");  		atomic_dec(&dest_se_deve->pr_ref_count);  		smp_mb__after_atomic_dec();  		dest_se_deve = NULL; -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		ret = -EINVAL; +		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  		goto out;  	} @@ -3625,8 +3486,7 @@ after_iport_check:  		pr_warn("SPC-3 PR REGISTER_AND_MOVE: No reservation"  			" currently held\n");  		spin_unlock(&dev->dev_reservation_lock); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		ret = -EINVAL; +		ret = TCM_INVALID_CDB_FIELD;  		goto out;  	}  	/* @@ -3639,8 +3499,7 @@ after_iport_check:  		pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T"  			" Nexus is not reservation holder\n");  		spin_unlock(&dev->dev_reservation_lock); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		ret = -EINVAL; +		ret = TCM_RESERVATION_CONFLICT;  		goto out;  	}  	/* @@ -3658,8 +3517,7 @@ after_iport_check:  			" reservation for type: %s\n",  			core_scsi3_pr_dump_type(pr_res_holder->pr_res_type));  		spin_unlock(&dev->dev_reservation_lock); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		ret = -EINVAL; +		ret = TCM_RESERVATION_CONFLICT;  		goto out;  	}  	pr_res_nacl = pr_res_holder->pr_reg_nacl; @@ -3691,13 +3549,11 @@ after_iport_check:  	dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl,  					iport_ptr);  	if (!dest_pr_reg) { -		ret = core_scsi3_alloc_registration(cmd->se_dev, +		if (core_scsi3_alloc_registration(cmd->se_dev,  				dest_node_acl, dest_se_deve, iport_ptr, -				sa_res_key, 0, aptpl, 2, 1); -		if (ret != 0) { +				sa_res_key, 0, aptpl, 2, 1)) {  			spin_unlock(&dev->dev_reservation_lock); -			cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -			ret = -EINVAL; +			ret = TCM_INVALID_PARAMETER_LIST;  			goto out;  		}  		dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, @@ -3768,12 +3624,12 @@ after_iport_check:  				" REGISTER_AND_MOVE\n");  	} else {  		pr_tmpl->pr_aptpl_active = 1; -		ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, +		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,  				&dest_pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len); -		if (!ret) +				pr_tmpl->pr_aptpl_buf_len)) {  			pr_debug("SPC-3 PR: Set APTPL Bit Activated for"  					" REGISTER_AND_MOVE\n"); +		}  	}  	transport_kunmap_data_sg(cmd); @@ -3788,6 +3644,8 @@ out:  	if (dest_node_acl)  		core_scsi3_nodeacl_undepend_item(dest_node_acl);  	core_scsi3_tpg_undepend_item(dest_se_tpg); + +out_put_pr_reg:  	core_scsi3_put_pr_reg(pr_reg);  	return ret;  } @@ -3805,14 +3663,15 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)  /*   * See spc4r17 section 6.14 Table 170   */ -int target_scsi3_emulate_pr_out(struct se_cmd *cmd) +sense_reason_t +target_scsi3_emulate_pr_out(struct se_cmd *cmd)  {  	unsigned char *cdb = &cmd->t_task_cdb[0];  	unsigned char *buf;  	u64 res_key, sa_res_key;  	int sa, scope, type, aptpl;  	int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; -	int ret; +	sense_reason_t ret;  	/*  	 * Following spc2r20 5.5.1 Reservations overview: @@ -3823,32 +3682,26 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)  	 * initiator or service action and shall terminate with a RESERVATION  	 * CONFLICT status.  	 */ -	if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { +	if (cmd->se_dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) {  		pr_err("Received PERSISTENT_RESERVE CDB while legacy"  			" SPC-2 reservation is held, returning"  			" RESERVATION_CONFLICT\n"); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		ret = -EINVAL; -		goto out; +		return TCM_RESERVATION_CONFLICT;  	}  	/*  	 * FIXME: A NULL struct se_session pointer means an this is not coming from  	 * a $FABRIC_MOD's nexus, but from internal passthrough ops.  	 */ -	if (!cmd->se_sess) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		ret = -EINVAL; -		goto out; -	} +	if (!cmd->se_sess) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	if (cmd->data_length < 24) {  		pr_warn("SPC-PR: Received PR OUT parameter list"  			" length too small: %u\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; -		goto out; +		return TCM_INVALID_PARAMETER_LIST;  	} +  	/*  	 * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB)  	 */ @@ -3857,6 +3710,9 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)  	type = (cdb[2] & 0x0f);  	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +  	/*  	 * From PERSISTENT_RESERVE_OUT parameter list (payload)  	 */ @@ -3880,11 +3736,8 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)  	/*  	 * SPEC_I_PT=1 is only valid for Service action: REGISTER  	 */ -	if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; -		goto out; -	} +	if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) +		return TCM_INVALID_PARAMETER_LIST;  	/*  	 * From spc4r17 section 6.14: @@ -3899,10 +3752,9 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)  	    (cmd->data_length != 24)) {  		pr_warn("SPC-PR: Received PR OUT illegal parameter"  			" list length: %u\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; -		ret = -EINVAL; -		goto out; +		return TCM_INVALID_PARAMETER_LIST;  	} +  	/*  	 * (core_scsi3_emulate_pro_* function parameters  	 * are defined by spc4r17 Table 174: @@ -3941,12 +3793,9 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)  	default:  		pr_err("Unknown PERSISTENT_RESERVE_OUT service"  			" action: 0x%02x\n", cdb[1] & 0x1f); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		ret = -EINVAL; -		break; +		return TCM_INVALID_CDB_FIELD;  	} -out:  	if (!ret)  		target_complete_cmd(cmd, GOOD);  	return ret; @@ -3957,10 +3806,10 @@ out:   *   * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160   */ -static int core_scsi3_pri_read_keys(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_read_keys(struct se_cmd *cmd)  { -	struct se_device *se_dev = cmd->se_dev; -	struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; +	struct se_device *dev = cmd->se_dev;  	struct t10_pr_registration *pr_reg;  	unsigned char *buf;  	u32 add_len = 0, off = 8; @@ -3968,18 +3817,20 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd)  	if (cmd->data_length < 8) {  		pr_err("PRIN SA READ_KEYS SCSI Data Length: %u"  			" too small\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	buf = transport_kmap_data_sg(cmd); -	buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); -	buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); -	buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); -	buf[3] = (su_dev->t10_pr.pr_generation & 0xff); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	spin_lock(&su_dev->t10_pr.registration_lock); -	list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, +	buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); +	buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); +	buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); +	buf[3] = (dev->t10_pr.pr_generation & 0xff); + +	spin_lock(&dev->t10_pr.registration_lock); +	list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,  			pr_reg_list) {  		/*  		 * Check for overflow of 8byte PRI READ_KEYS payload and @@ -3999,7 +3850,7 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd)  		add_len += 8;  	} -	spin_unlock(&su_dev->t10_pr.registration_lock); +	spin_unlock(&dev->t10_pr.registration_lock);  	buf[4] = ((add_len >> 24) & 0xff);  	buf[5] = ((add_len >> 16) & 0xff); @@ -4016,10 +3867,10 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd)   *   * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162   */ -static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_read_reservation(struct se_cmd *cmd)  { -	struct se_device *se_dev = cmd->se_dev; -	struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; +	struct se_device *dev = cmd->se_dev;  	struct t10_pr_registration *pr_reg;  	unsigned char *buf;  	u64 pr_res_key; @@ -4028,18 +3879,20 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd)  	if (cmd->data_length < 8) {  		pr_err("PRIN SA READ_RESERVATIONS SCSI Data Length: %u"  			" too small\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	buf = transport_kmap_data_sg(cmd); -	buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); -	buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); -	buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); -	buf[3] = (su_dev->t10_pr.pr_generation & 0xff); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	spin_lock(&se_dev->dev_reservation_lock); -	pr_reg = se_dev->dev_pr_res_holder; +	buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); +	buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); +	buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); +	buf[3] = (dev->t10_pr.pr_generation & 0xff); + +	spin_lock(&dev->dev_reservation_lock); +	pr_reg = dev->dev_pr_res_holder;  	if (pr_reg) {  		/*  		 * Set the hardcoded Additional Length @@ -4090,7 +3943,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd)  	}  err: -	spin_unlock(&se_dev->dev_reservation_lock); +	spin_unlock(&dev->dev_reservation_lock);  	transport_kunmap_data_sg(cmd);  	return 0; @@ -4101,21 +3954,23 @@ err:   *   * See spc4r17 section 6.13.4 Table 165   */ -static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_report_capabilities(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; -	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	unsigned char *buf;  	u16 add_len = 8; /* Hardcoded to 8. */  	if (cmd->data_length < 6) {  		pr_err("PRIN SA REPORT_CAPABILITIES SCSI Data Length:"  			" %u too small\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	buf[0] = ((add_len << 8) & 0xff);  	buf[1] = (add_len & 0xff); @@ -4157,14 +4012,14 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd)   *   * See spc4r17 section 6.13.5 Table 168 and 169   */ -static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_read_full_status(struct se_cmd *cmd)  { -	struct se_device *se_dev = cmd->se_dev; +	struct se_device *dev = cmd->se_dev;  	struct se_node_acl *se_nacl; -	struct se_subsystem_dev *su_dev = se_dev->se_sub_dev;  	struct se_portal_group *se_tpg;  	struct t10_pr_registration *pr_reg, *pr_reg_tmp; -	struct t10_reservation *pr_tmpl = &se_dev->se_sub_dev->t10_pr; +	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	unsigned char *buf;  	u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;  	u32 off = 8; /* off into first Full Status descriptor */ @@ -4173,16 +4028,17 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)  	if (cmd->data_length < 8) {  		pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u"  			" too small\n", cmd->data_length); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); -	buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); -	buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); -	buf[3] = (su_dev->t10_pr.pr_generation & 0xff); +	buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); +	buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); +	buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); +	buf[3] = (dev->t10_pr.pr_generation & 0xff);  	spin_lock(&pr_tmpl->registration_lock);  	list_for_each_entry_safe(pr_reg, pr_reg_tmp, @@ -4303,9 +4159,10 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)  	return 0;  } -int target_scsi3_emulate_pr_in(struct se_cmd *cmd) +sense_reason_t +target_scsi3_emulate_pr_in(struct se_cmd *cmd)  { -	int ret; +	sense_reason_t ret;  	/*  	 * Following spc2r20 5.5.1 Reservations overview: @@ -4316,12 +4173,11 @@ int target_scsi3_emulate_pr_in(struct se_cmd *cmd)  	 * initiator or service action and shall terminate with a RESERVATION  	 * CONFLICT status.  	 */ -	if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { +	if (cmd->se_dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) {  		pr_err("Received PERSISTENT_RESERVE CDB while legacy"  			" SPC-2 reservation is held, returning"  			" RESERVATION_CONFLICT\n"); -		cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -		return -EINVAL; +		return TCM_RESERVATION_CONFLICT;  	}  	switch (cmd->t_task_cdb[1] & 0x1f) { @@ -4340,9 +4196,7 @@ int target_scsi3_emulate_pr_in(struct se_cmd *cmd)  	default:  		pr_err("Unknown PERSISTENT_RESERVE_IN service"  			" action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		ret = -EINVAL; -		break; +		return TCM_INVALID_CDB_FIELD;  	}  	if (!ret) @@ -4350,56 +4204,25 @@ int target_scsi3_emulate_pr_in(struct se_cmd *cmd)  	return ret;  } -static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) -{ -	return 0; -} - -static int core_pt_seq_non_holder( -	struct se_cmd *cmd, -	unsigned char *cdb, -	u32 pr_reg_type) +sense_reason_t +target_check_reservation(struct se_cmd *cmd)  { -	return 0; -} +	struct se_device *dev = cmd->se_dev; +	sense_reason_t ret; -int core_setup_reservations(struct se_device *dev, int force_pt) -{ -	struct se_subsystem_dev *su_dev = dev->se_sub_dev; -	struct t10_reservation *rest = &su_dev->t10_pr; -	/* -	 * If this device is from Target_Core_Mod/pSCSI, use the reservations -	 * of the Underlying SCSI hardware.  In Linux/SCSI terms, this can -	 * cause a problem because libata and some SATA RAID HBAs appear -	 * under Linux/SCSI, but to emulate reservations themselves. -	 */ -	if (((dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && -	    !(dev->se_sub_dev->se_dev_attrib.emulate_reservations)) || force_pt) { -		rest->res_type = SPC_PASSTHROUGH; -		rest->pr_ops.t10_reservation_check = &core_pt_reservation_check; -		rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder; -		pr_debug("%s: Using SPC_PASSTHROUGH, no reservation" -			" emulation\n", dev->transport->name); +	if (!cmd->se_sess) +		return 0; +	if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) +		return 0; +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)  		return 0; -	} -	/* -	 * If SPC-3 or above is reported by real or emulated struct se_device, -	 * use emulated Persistent Reservations. -	 */ -	if (dev->transport->get_device_rev(dev) >= SCSI_3) { -		rest->res_type = SPC3_PERSISTENT_RESERVATIONS; -		rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check; -		rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder; -		pr_debug("%s: Using SPC3_PERSISTENT_RESERVATIONS" -			" emulation\n", dev->transport->name); -	} else { -		rest->res_type = SPC2_RESERVATIONS; -		rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check; -		rest->pr_ops.t10_seq_non_holder = -				&core_scsi2_reservation_seq_non_holder; -		pr_debug("%s: Using SPC2_RESERVATIONS emulation\n", -			dev->transport->name); -	} -	return 0; +	spin_lock(&dev->dev_reservation_lock); +	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) +		ret = target_scsi2_reservation_check(cmd); +	else +		ret = target_scsi3_pr_reservation_check(cmd); +	spin_unlock(&dev->dev_reservation_lock); + +	return ret;  } diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index af6c460d886d..b4a004247ab2 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -47,8 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache;  extern int core_pr_dump_initiator_port(struct t10_pr_registration *,  			char *, u32); -extern int target_scsi2_reservation_release(struct se_cmd *); -extern int target_scsi2_reservation_reserve(struct se_cmd *); +extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *); +extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *);  extern int core_scsi3_alloc_aptpl_registration(  			struct t10_reservation *, u64,  			unsigned char *, unsigned char *, u32, @@ -61,8 +61,8 @@ extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *,  extern void core_scsi3_free_all_registrations(struct se_device *);  extern unsigned char *core_scsi3_pr_dump_type(int); -extern int target_scsi3_emulate_pr_in(struct se_cmd *); -extern int target_scsi3_emulate_pr_out(struct se_cmd *); -extern int core_setup_reservations(struct se_device *, int); +extern sense_reason_t target_scsi3_emulate_pr_in(struct se_cmd *); +extern sense_reason_t target_scsi3_emulate_pr_out(struct se_cmd *); +extern sense_reason_t target_check_reservation(struct se_cmd *);  #endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 617c086a8a02..2bcfd79cf595 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -3,10 +3,7 @@   *   * This file contains the generic target mode <-> Linux SCSI subsystem plugin.   * - * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2003-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -53,9 +50,14 @@  #define ISPRINT(a)  ((a >= ' ') && (a <= '~')) +static inline struct pscsi_dev_virt *PSCSI_DEV(struct se_device *dev) +{ +	return container_of(dev, struct pscsi_dev_virt, dev); +} +  static struct se_subsystem_api pscsi_template; -static int pscsi_execute_cmd(struct se_cmd *cmd); +static sense_reason_t pscsi_execute_cmd(struct se_cmd *cmd);  static void pscsi_req_done(struct request *, int);  /*	pscsi_attach_hba(): @@ -219,7 +221,7 @@ pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn)  	snprintf(&wwn->unit_serial[0], INQUIRY_VPD_SERIAL_LEN, "%s", &buf[4]); -	wwn->t10_sub_dev->su_dev_flags |= SDF_FIRMWARE_VPD_UNIT_SERIAL; +	wwn->t10_dev->dev_flags |= DF_FIRMWARE_VPD_UNIT_SERIAL;  	kfree(buf);  	return 0; @@ -299,23 +301,13 @@ out:  	kfree(buf);  } -/*	pscsi_add_device_to_list(): - * - * - */ -static struct se_device *pscsi_add_device_to_list( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	struct pscsi_dev_virt *pdv, -	struct scsi_device *sd, -	int dev_flags) +static int pscsi_add_device_to_list(struct se_device *dev, +		struct scsi_device *sd)  { -	struct se_device *dev; -	struct se_dev_limits dev_limits; -	struct request_queue *q; -	struct queue_limits *limits; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); +	struct request_queue *q = sd->request_queue; -	memset(&dev_limits, 0, sizeof(struct se_dev_limits)); +	pdv->pdv_sd = sd;  	if (!sd->queue_depth) {  		sd->queue_depth = PSCSI_DEFAULT_QUEUEDEPTH; @@ -324,54 +316,27 @@ static struct se_device *pscsi_add_device_to_list(  			" queue_depth to %d\n", sd->channel, sd->id,  				sd->lun, sd->queue_depth);  	} -	/* -	 * Setup the local scope queue_limits from struct request_queue->limits -	 * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. -	 */ -	q = sd->request_queue; -	limits = &dev_limits.limits; -	limits->logical_block_size = sd->sector_size; -	limits->max_hw_sectors = min_t(int, sd->host->max_sectors, queue_max_hw_sectors(q)); -	limits->max_sectors = min_t(int, sd->host->max_sectors, queue_max_sectors(q)); -	dev_limits.hw_queue_depth = sd->queue_depth; -	dev_limits.queue_depth = sd->queue_depth; -	/* -	 * Setup our standard INQUIRY info into se_dev->t10_wwn -	 */ -	pscsi_set_inquiry_info(sd, &se_dev->t10_wwn); + +	dev->dev_attrib.hw_block_size = sd->sector_size; +	dev->dev_attrib.hw_max_sectors = +		min_t(int, sd->host->max_sectors, queue_max_hw_sectors(q)); +	dev->dev_attrib.hw_queue_depth = sd->queue_depth;  	/* -	 * Set the pointer pdv->pdv_sd to from passed struct scsi_device, -	 * which has already been referenced with Linux SCSI code with -	 * scsi_device_get() in this file's pscsi_create_virtdevice(). -	 * -	 * The passthrough operations called by the transport_add_device_* -	 * function below will require this pointer to be set for passthroug -	 *  ops. -	 * -	 * For the shutdown case in pscsi_free_device(), this struct -	 * scsi_device  reference is released with Linux SCSI code -	 * scsi_device_put() and the pdv->pdv_sd cleared. +	 * Setup our standard INQUIRY info into se_dev->t10_wwn  	 */ -	pdv->pdv_sd = sd; -	dev = transport_add_device_to_core_hba(hba, &pscsi_template, -				se_dev, dev_flags, pdv, -				&dev_limits, NULL, NULL); -	if (!dev) { -		pdv->pdv_sd = NULL; -		return NULL; -	} +	pscsi_set_inquiry_info(sd, &dev->t10_wwn);  	/*  	 * Locate VPD WWN Information used for various purposes within  	 * the Storage Engine.  	 */ -	if (!pscsi_get_inquiry_vpd_serial(sd, &se_dev->t10_wwn)) { +	if (!pscsi_get_inquiry_vpd_serial(sd, &dev->t10_wwn)) {  		/*  		 * If VPD Unit Serial returned GOOD status, try  		 * VPD Device Identification page (0x83).  		 */ -		pscsi_get_inquiry_vpd_device_ident(sd, &se_dev->t10_wwn); +		pscsi_get_inquiry_vpd_device_ident(sd, &dev->t10_wwn);  	}  	/* @@ -379,10 +344,11 @@ static struct se_device *pscsi_add_device_to_list(  	 */  	if (sd->type == TYPE_TAPE)  		pscsi_tape_read_blocksize(dev, sd); -	return dev; +	return 0;  } -static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *pscsi_alloc_device(struct se_hba *hba, +		const char *name)  {  	struct pscsi_dev_virt *pdv; @@ -391,139 +357,125 @@ static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name)  		pr_err("Unable to allocate memory for struct pscsi_dev_virt\n");  		return NULL;  	} -	pdv->pdv_se_hba = hba;  	pr_debug("PSCSI: Allocated pdv: %p for %s\n", pdv, name); -	return pdv; +	return &pdv->dev;  }  /*   * Called with struct Scsi_Host->host_lock called.   */ -static struct se_device *pscsi_create_type_disk( -	struct scsi_device *sd, -	struct pscsi_dev_virt *pdv, -	struct se_subsystem_dev *se_dev, -	struct se_hba *hba) +static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd)  	__releases(sh->host_lock)  { -	struct se_device *dev; -	struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);  	struct Scsi_Host *sh = sd->host;  	struct block_device *bd; -	u32 dev_flags = 0; +	int ret;  	if (scsi_device_get(sd)) {  		pr_err("scsi_device_get() failed for %d:%d:%d:%d\n",  			sh->host_no, sd->channel, sd->id, sd->lun);  		spin_unlock_irq(sh->host_lock); -		return NULL; +		return -EIO;  	}  	spin_unlock_irq(sh->host_lock);  	/*  	 * Claim exclusive struct block_device access to struct scsi_device  	 * for TYPE_DISK using supplied udev_path  	 */ -	bd = blkdev_get_by_path(se_dev->se_dev_udev_path, +	bd = blkdev_get_by_path(dev->udev_path,  				FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv);  	if (IS_ERR(bd)) {  		pr_err("pSCSI: blkdev_get_by_path() failed\n");  		scsi_device_put(sd); -		return NULL; +		return PTR_ERR(bd);  	}  	pdv->pdv_bd = bd; -	dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); -	if (!dev) { +	ret = pscsi_add_device_to_list(dev, sd); +	if (ret) {  		blkdev_put(pdv->pdv_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);  		scsi_device_put(sd); -		return NULL; +		return ret;  	} +  	pr_debug("CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%d\n",  		phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun); - -	return dev; +	return 0;  }  /*   * Called with struct Scsi_Host->host_lock called.   */ -static struct se_device *pscsi_create_type_rom( -	struct scsi_device *sd, -	struct pscsi_dev_virt *pdv, -	struct se_subsystem_dev *se_dev, -	struct se_hba *hba) +static int pscsi_create_type_rom(struct se_device *dev, struct scsi_device *sd)  	__releases(sh->host_lock)  { -	struct se_device *dev; -	struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;  	struct Scsi_Host *sh = sd->host; -	u32 dev_flags = 0; +	int ret;  	if (scsi_device_get(sd)) {  		pr_err("scsi_device_get() failed for %d:%d:%d:%d\n",  			sh->host_no, sd->channel, sd->id, sd->lun);  		spin_unlock_irq(sh->host_lock); -		return NULL; +		return -EIO;  	}  	spin_unlock_irq(sh->host_lock); -	dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); -	if (!dev) { +	ret = pscsi_add_device_to_list(dev, sd); +	if (ret) {  		scsi_device_put(sd); -		return NULL; +		return ret;  	}  	pr_debug("CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n",  		phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,  		sd->channel, sd->id, sd->lun); -	return dev; +	return 0;  }  /* - *Called with struct Scsi_Host->host_lock called. + * Called with struct Scsi_Host->host_lock called.   */ -static struct se_device *pscsi_create_type_other( -	struct scsi_device *sd, -	struct pscsi_dev_virt *pdv, -	struct se_subsystem_dev *se_dev, -	struct se_hba *hba) +static int pscsi_create_type_other(struct se_device *dev, +		struct scsi_device *sd)  	__releases(sh->host_lock)  { -	struct se_device *dev; -	struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;  	struct Scsi_Host *sh = sd->host; -	u32 dev_flags = 0; +	int ret;  	spin_unlock_irq(sh->host_lock); -	dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); -	if (!dev) -		return NULL; +	ret = pscsi_add_device_to_list(dev, sd); +	if (ret) +		return ret;  	pr_debug("CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n",  		phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,  		sd->channel, sd->id, sd->lun); - -	return dev; +	return 0;  } -static struct se_device *pscsi_create_virtdevice( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	void *p) +static int pscsi_configure_device(struct se_device *dev)  { -	struct pscsi_dev_virt *pdv = p; -	struct se_device *dev; +	struct se_hba *hba = dev->se_hba; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);  	struct scsi_device *sd; -	struct pscsi_hba_virt *phv = hba->hba_ptr; +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;  	struct Scsi_Host *sh = phv->phv_lld_host;  	int legacy_mode_enable = 0; +	int ret; -	if (!pdv) { -		pr_err("Unable to locate struct pscsi_dev_virt" -				" parameter\n"); -		return ERR_PTR(-EINVAL); +	if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) || +	    !(pdv->pdv_flags & PDF_HAS_TARGET_ID) || +	    !(pdv->pdv_flags & PDF_HAS_LUN_ID)) { +		pr_err("Missing scsi_channel_id=, scsi_target_id= and" +			" scsi_lun_id= parameters\n"); +		return -EINVAL;  	} +  	/*  	 * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the  	 * struct Scsi_Host we will need to bring the TCM/pSCSI object online @@ -532,16 +484,16 @@ static struct se_device *pscsi_create_virtdevice(  		if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) {  			pr_err("pSCSI: Unable to locate struct"  				" Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); -			return ERR_PTR(-ENODEV); +			return -ENODEV;  		}  		/*  		 * For the newer PHV_VIRTUAL_HOST_ID struct scsi_device  		 * reference, we enforce that udev_path has been set  		 */ -		if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { +		if (!(dev->dev_flags & DF_USING_UDEV_PATH)) {  			pr_err("pSCSI: udev_path attribute has not"  				" been set before ENABLE=1\n"); -			return ERR_PTR(-EINVAL); +			return -EINVAL;  		}  		/*  		 * If no scsi_host_id= was passed for PHV_VIRTUAL_HOST_ID, @@ -549,17 +501,14 @@ static struct se_device *pscsi_create_virtdevice(  		 * and enable for PHV_LLD_SCSI_HOST_NO mode.  		 */  		if (!(pdv->pdv_flags & PDF_HAS_VIRT_HOST_ID)) { -			spin_lock(&hba->device_lock); -			if (!list_empty(&hba->hba_dev_list)) { +			if (hba->dev_count) {  				pr_err("pSCSI: Unable to set hba_mode"  					" with active devices\n"); -				spin_unlock(&hba->device_lock); -				return ERR_PTR(-EEXIST); +				return -EEXIST;  			} -			spin_unlock(&hba->device_lock);  			if (pscsi_pmode_enable_hba(hba, 1) != 1) -				return ERR_PTR(-ENODEV); +				return -ENODEV;  			legacy_mode_enable = 1;  			hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; @@ -569,14 +518,14 @@ static struct se_device *pscsi_create_virtdevice(  			if (IS_ERR(sh)) {  				pr_err("pSCSI: Unable to locate"  					" pdv_host_id: %d\n", pdv->pdv_host_id); -				return ERR_CAST(sh); +				return PTR_ERR(sh);  			}  		}  	} else {  		if (phv->phv_mode == PHV_VIRTUAL_HOST_ID) {  			pr_err("pSCSI: PHV_VIRTUAL_HOST_ID set while"  				" struct Scsi_Host exists\n"); -			return ERR_PTR(-EEXIST); +			return -EEXIST;  		}  	} @@ -593,17 +542,17 @@ static struct se_device *pscsi_create_virtdevice(  		 */  		switch (sd->type) {  		case TYPE_DISK: -			dev = pscsi_create_type_disk(sd, pdv, se_dev, hba); +			ret = pscsi_create_type_disk(dev, sd);  			break;  		case TYPE_ROM: -			dev = pscsi_create_type_rom(sd, pdv, se_dev, hba); +			ret = pscsi_create_type_rom(dev, sd);  			break;  		default: -			dev = pscsi_create_type_other(sd, pdv, se_dev, hba); +			ret = pscsi_create_type_other(dev, sd);  			break;  		} -		if (!dev) { +		if (ret) {  			if (phv->phv_mode == PHV_VIRTUAL_HOST_ID)  				scsi_host_put(sh);  			else if (legacy_mode_enable) { @@ -611,9 +560,9 @@ static struct se_device *pscsi_create_virtdevice(  				hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;  			}  			pdv->pdv_sd = NULL; -			return ERR_PTR(-ENODEV); +			return ret;  		} -		return dev; +		return 0;  	}  	spin_unlock_irq(sh->host_lock); @@ -627,17 +576,13 @@ static struct se_device *pscsi_create_virtdevice(  		hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;  	} -	return ERR_PTR(-ENODEV); +	return -ENODEV;  } -/*	pscsi_free_device(): (Part of se_subsystem_api_t template) - * - * - */ -static void pscsi_free_device(void *p) +static void pscsi_free_device(struct se_device *dev)  { -	struct pscsi_dev_virt *pdv = p; -	struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;  	struct scsi_device *sd = pdv->pdv_sd;  	if (sd) { @@ -670,7 +615,7 @@ static void pscsi_free_device(void *p)  static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,  				     unsigned char *sense_buffer)  { -	struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev);  	struct scsi_device *sd = pdv->pdv_sd;  	int result;  	struct pscsi_plugin_task *pt = cmd->priv; @@ -694,7 +639,11 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,  	if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&  	     (status_byte(result) << 1) == SAM_STAT_GOOD) {  		if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { -			unsigned char *buf = transport_kmap_data_sg(cmd); +			unsigned char *buf; + +			buf = transport_kmap_data_sg(cmd); +			if (!buf) +				; /* XXX: TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE */  			if (cdb[0] == MODE_SENSE_10) {  				if (!(buf[3] & 0x80)) @@ -770,13 +719,11 @@ static match_table_t tokens = {  	{Opt_err, NULL}  }; -static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	const char *page, -	ssize_t count) +static ssize_t pscsi_set_configfs_dev_params(struct se_device *dev, +		const char *page, ssize_t count)  { -	struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; -	struct pscsi_hba_virt *phv = hba->hba_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;  	char *orig, *ptr, *opts;  	substring_t args[MAX_OPT_ARGS];  	int ret = 0, arg, token; @@ -841,29 +788,10 @@ out:  	return (!ret) ? count : ret;  } -static ssize_t pscsi_check_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev) +static ssize_t pscsi_show_configfs_dev_params(struct se_device *dev, char *b)  { -	struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; - -	if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) || -	    !(pdv->pdv_flags & PDF_HAS_TARGET_ID) || -	    !(pdv->pdv_flags & PDF_HAS_LUN_ID)) { -		pr_err("Missing scsi_channel_id=, scsi_target_id= and" -			" scsi_lun_id= parameters\n"); -		return -EINVAL; -	} - -	return 0; -} - -static ssize_t pscsi_show_configfs_dev_params(struct se_hba *hba, -					      struct se_subsystem_dev *se_dev, -					      char *b) -{ -	struct pscsi_hba_virt *phv = hba->hba_ptr; -        struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; +	struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);  	struct scsi_device *sd = pdv->pdv_sd;  	unsigned char host_id[16];  	ssize_t bl; @@ -929,11 +857,11 @@ static inline struct bio *pscsi_get_bio(int sg_num)  	return bio;  } -static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, -		u32 sgl_nents, enum dma_data_direction data_direction, -		struct bio **hbio) +static sense_reason_t +pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, +		enum dma_data_direction data_direction, struct bio **hbio)  { -	struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev);  	struct bio *bio = NULL, *tbio = NULL;  	struct page *page;  	struct scatterlist *sg; @@ -1019,7 +947,7 @@ static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl,  		}  	} -	return sgl_nents; +	return 0;  fail:  	while (*hbio) {  		bio = *hbio; @@ -1027,8 +955,7 @@ fail:  		bio->bi_next = NULL;  		bio_endio(bio, 0);	/* XXX: should be error */  	} -	cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	return -ENOMEM; +	return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  }  /* @@ -1055,17 +982,13 @@ static inline void pscsi_clear_cdb_lun(unsigned char *cdb)  	}  } -static int pscsi_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +pscsi_parse_cdb(struct se_cmd *cmd)  {  	unsigned char *cdb = cmd->t_task_cdb; -	unsigned int dummy_size; -	int ret; -	if (cmd->se_cmd_flags & SCF_BIDI) { -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -		return -EINVAL; -	} +	if (cmd->se_cmd_flags & SCF_BIDI) +		return TCM_UNSUPPORTED_SCSI_OPCODE;  	pscsi_clear_cdb_lun(cdb); @@ -1076,10 +999,8 @@ static int pscsi_parse_cdb(struct se_cmd *cmd)  	 */  	switch (cdb[0]) {  	case REPORT_LUNS: -		ret = spc_parse_cdb(cmd, &dummy_size); -		if (ret) -			return ret; -		break; +		cmd->execute_cmd = spc_emulate_report_luns; +		return 0;  	case READ_6:  	case READ_10:  	case READ_12: @@ -1093,22 +1014,21 @@ static int pscsi_parse_cdb(struct se_cmd *cmd)  		/* FALLTHROUGH*/  	default:  		cmd->execute_cmd = pscsi_execute_cmd; -		break; +		return 0;  	} - -	return 0;  } -static int pscsi_execute_cmd(struct se_cmd *cmd) +static sense_reason_t +pscsi_execute_cmd(struct se_cmd *cmd)  {  	struct scatterlist *sgl = cmd->t_data_sg;  	u32 sgl_nents = cmd->t_data_nents;  	enum dma_data_direction data_direction = cmd->data_direction; -	struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev);  	struct pscsi_plugin_task *pt;  	struct request *req;  	struct bio *hbio; -	int ret; +	sense_reason_t ret;  	/*  	 * Dynamically alloc cdb space, since it may be larger than @@ -1116,8 +1036,7 @@ static int pscsi_execute_cmd(struct se_cmd *cmd)  	 */  	pt = kzalloc(sizeof(*pt) + scsi_command_size(cmd->t_task_cdb), GFP_KERNEL);  	if (!pt) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		return -ENOMEM; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	cmd->priv = pt; @@ -1131,24 +1050,21 @@ static int pscsi_execute_cmd(struct se_cmd *cmd)  		if (!req || IS_ERR(req)) {  			pr_err("PSCSI: blk_get_request() failed: %ld\n",  					req ? IS_ERR(req) : -ENOMEM); -			cmd->scsi_sense_reason = -				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  			goto fail;  		}  	} else {  		BUG_ON(!cmd->data_length);  		ret = pscsi_map_sg(cmd, sgl, sgl_nents, data_direction, &hbio); -		if (ret < 0) { -			cmd->scsi_sense_reason = -				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		if (ret)  			goto fail; -		}  		req = blk_make_request(pdv->pdv_sd->request_queue, hbio,  				       GFP_KERNEL);  		if (IS_ERR(req)) {  			pr_err("pSCSI: blk_make_request() failed\n"); +			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  			goto fail_free_bio;  		}  	} @@ -1179,22 +1095,10 @@ fail_free_bio:  		bio->bi_next = NULL;  		bio_endio(bio, 0);	/* XXX: should be error */  	} -	cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  fail:  	kfree(pt); -	return -ENOMEM; -} - -/*	pscsi_get_device_rev(): - * - * - */ -static u32 pscsi_get_device_rev(struct se_device *dev) -{ -	struct pscsi_dev_virt *pdv = dev->dev_ptr; -	struct scsi_device *sd = pdv->pdv_sd; - -	return (sd->scsi_level - 1) ? sd->scsi_level - 1 : 1; +	return ret;  }  /*	pscsi_get_device_type(): @@ -1203,7 +1107,7 @@ static u32 pscsi_get_device_rev(struct se_device *dev)   */  static u32 pscsi_get_device_type(struct se_device *dev)  { -	struct pscsi_dev_virt *pdv = dev->dev_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);  	struct scsi_device *sd = pdv->pdv_sd;  	return sd->type; @@ -1211,7 +1115,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)  static sector_t pscsi_get_blocks(struct se_device *dev)  { -	struct pscsi_dev_virt *pdv = dev->dev_ptr; +	struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);  	if (pdv->pdv_bd && pdv->pdv_bd->bd_part)  		return pdv->pdv_bd->bd_part->nr_sects; @@ -1243,7 +1147,6 @@ static void pscsi_req_done(struct request *req, int uptodate)  		pr_debug("PSCSI Host Byte exception at cmd: %p CDB:"  			" 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0],  			pt->pscsi_result); -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;  		target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);  		break;  	} @@ -1259,15 +1162,13 @@ static struct se_subsystem_api pscsi_template = {  	.attach_hba		= pscsi_attach_hba,  	.detach_hba		= pscsi_detach_hba,  	.pmode_enable_hba	= pscsi_pmode_enable_hba, -	.allocate_virtdevice	= pscsi_allocate_virtdevice, -	.create_virtdevice	= pscsi_create_virtdevice, +	.alloc_device		= pscsi_alloc_device, +	.configure_device	= pscsi_configure_device,  	.free_device		= pscsi_free_device,  	.transport_complete	= pscsi_transport_complete,  	.parse_cdb		= pscsi_parse_cdb, -	.check_configfs_dev_params = pscsi_check_configfs_dev_params,  	.set_configfs_dev_params = pscsi_set_configfs_dev_params,  	.show_configfs_dev_params = pscsi_show_configfs_dev_params, -	.get_device_rev		= pscsi_get_device_rev,  	.get_device_type	= pscsi_get_device_type,  	.get_blocks		= pscsi_get_blocks,  }; diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h index bc1e5e11eca0..1bd757dff8ee 100644 --- a/drivers/target/target_core_pscsi.h +++ b/drivers/target/target_core_pscsi.h @@ -37,6 +37,7 @@ struct pscsi_plugin_task {  #define PDF_HAS_VIRT_HOST_ID	0x20  struct pscsi_dev_virt { +	struct se_device dev;  	int	pdv_flags;  	int	pdv_host_id;  	int	pdv_channel_id; @@ -44,7 +45,6 @@ struct pscsi_dev_virt {  	int	pdv_lun_id;  	struct block_device *pdv_bd;  	struct scsi_device *pdv_sd; -	struct se_hba *pdv_se_hba;  } ____cacheline_aligned;  typedef enum phv_modes { diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d00bbe33ff8b..0457de362e68 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -4,10 +4,7 @@   * This file contains the Storage Engine <-> Ramdisk transport   * specific functions.   * - * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2003-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -41,7 +38,10 @@  #include "target_core_rd.h" -static struct se_subsystem_api rd_mcp_template; +static inline struct rd_dev *RD_DEV(struct se_device *dev) +{ +	return container_of(dev, struct rd_dev, dev); +}  /*	rd_attach_hba(): (Part of se_subsystem_api_t template)   * @@ -196,7 +196,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev)  	return 0;  } -static void *rd_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *rd_alloc_device(struct se_hba *hba, const char *name)  {  	struct rd_dev *rd_dev;  	struct rd_host *rd_host = hba->hba_ptr; @@ -209,39 +209,27 @@ static void *rd_allocate_virtdevice(struct se_hba *hba, const char *name)  	rd_dev->rd_host = rd_host; -	return rd_dev; +	return &rd_dev->dev;  } -static struct se_device *rd_create_virtdevice(struct se_hba *hba, -		struct se_subsystem_dev *se_dev, void *p) +static int rd_configure_device(struct se_device *dev)  { -	struct se_device *dev; -	struct se_dev_limits dev_limits; -	struct rd_dev *rd_dev = p; -	struct rd_host *rd_host = hba->hba_ptr; -	int dev_flags = 0, ret; -	char prod[16], rev[4]; +	struct rd_dev *rd_dev = RD_DEV(dev); +	struct rd_host *rd_host = dev->se_hba->hba_ptr; +	int ret; -	memset(&dev_limits, 0, sizeof(struct se_dev_limits)); +	if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) { +		pr_debug("Missing rd_pages= parameter\n"); +		return -EINVAL; +	}  	ret = rd_build_device_space(rd_dev);  	if (ret < 0)  		goto fail; -	snprintf(prod, 16, "RAMDISK-MCP"); -	snprintf(rev, 4, "%s", RD_MCP_VERSION); - -	dev_limits.limits.logical_block_size = RD_BLOCKSIZE; -	dev_limits.limits.max_hw_sectors = UINT_MAX; -	dev_limits.limits.max_sectors = UINT_MAX; -	dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; -	dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH; - -	dev = transport_add_device_to_core_hba(hba, -			&rd_mcp_template, se_dev, dev_flags, rd_dev, -			&dev_limits, prod, rev); -	if (!dev) -		goto fail; +	dev->dev_attrib.hw_block_size = RD_BLOCKSIZE; +	dev->dev_attrib.hw_max_sectors = UINT_MAX; +	dev->dev_attrib.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH;  	rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++; @@ -251,16 +239,16 @@ static struct se_device *rd_create_virtdevice(struct se_hba *hba,  		rd_dev->sg_table_count,  		(unsigned long)(rd_dev->rd_page_count * PAGE_SIZE)); -	return dev; +	return 0;  fail:  	rd_release_device_space(rd_dev); -	return ERR_PTR(ret); +	return ret;  } -static void rd_free_device(void *p) +static void rd_free_device(struct se_device *dev)  { -	struct rd_dev *rd_dev = p; +	struct rd_dev *rd_dev = RD_DEV(dev);  	rd_release_device_space(rd_dev);  	kfree(rd_dev); @@ -284,13 +272,14 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)  	return NULL;  } -static int rd_execute_rw(struct se_cmd *cmd) +static sense_reason_t +rd_execute_rw(struct se_cmd *cmd)  {  	struct scatterlist *sgl = cmd->t_data_sg;  	u32 sgl_nents = cmd->t_data_nents;  	enum dma_data_direction data_direction = cmd->data_direction;  	struct se_device *se_dev = cmd->se_dev; -	struct rd_dev *dev = se_dev->dev_ptr; +	struct rd_dev *dev = RD_DEV(se_dev);  	struct rd_dev_sg_table *table;  	struct scatterlist *rd_sg;  	struct sg_mapping_iter m; @@ -300,14 +289,14 @@ static int rd_execute_rw(struct se_cmd *cmd)  	u32 src_len;  	u64 tmp; -	tmp = cmd->t_task_lba * se_dev->se_sub_dev->se_dev_attrib.block_size; +	tmp = cmd->t_task_lba * se_dev->dev_attrib.block_size;  	rd_offset = do_div(tmp, PAGE_SIZE);  	rd_page = tmp;  	rd_size = cmd->data_length;  	table = rd_get_sg_table(dev, rd_page);  	if (!table) -		return -EINVAL; +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	rd_sg = &table->sg_table[rd_page - table->page_start_offset]; @@ -357,7 +346,7 @@ static int rd_execute_rw(struct se_cmd *cmd)  		table = rd_get_sg_table(dev, rd_page);  		if (!table) {  			sg_miter_stop(&m); -			return -EINVAL; +			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  		}  		/* since we increment, the first sg entry is correct */ @@ -378,13 +367,10 @@ static match_table_t tokens = {  	{Opt_err, NULL}  }; -static ssize_t rd_set_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	const char *page, -	ssize_t count) +static ssize_t rd_set_configfs_dev_params(struct se_device *dev, +		const char *page, ssize_t count)  { -	struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; +	struct rd_dev *rd_dev = RD_DEV(dev);  	char *orig, *ptr, *opts;  	substring_t args[MAX_OPT_ARGS];  	int ret = 0, arg, token; @@ -417,24 +403,10 @@ static ssize_t rd_set_configfs_dev_params(  	return (!ret) ? count : ret;  } -static ssize_t rd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) +static ssize_t rd_show_configfs_dev_params(struct se_device *dev, char *b)  { -	struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; +	struct rd_dev *rd_dev = RD_DEV(dev); -	if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) { -		pr_debug("Missing rd_pages= parameter\n"); -		return -EINVAL; -	} - -	return 0; -} - -static ssize_t rd_show_configfs_dev_params( -	struct se_hba *hba, -	struct se_subsystem_dev *se_dev, -	char *b) -{ -	struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;  	ssize_t bl = sprintf(b, "TCM RamDisk ID: %u  RamDisk Makeup: rd_mcp\n",  			rd_dev->rd_dev_id);  	bl += sprintf(b + bl, "        PAGES/PAGE_SIZE: %u*%lu" @@ -443,48 +415,40 @@ static ssize_t rd_show_configfs_dev_params(  	return bl;  } -static u32 rd_get_device_rev(struct se_device *dev) -{ -	return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ -} - -static u32 rd_get_device_type(struct se_device *dev) -{ -	return TYPE_DISK; -} -  static sector_t rd_get_blocks(struct se_device *dev)  { -	struct rd_dev *rd_dev = dev->dev_ptr; +	struct rd_dev *rd_dev = RD_DEV(dev); +  	unsigned long long blocks_long = ((rd_dev->rd_page_count * PAGE_SIZE) / -			dev->se_sub_dev->se_dev_attrib.block_size) - 1; +			dev->dev_attrib.block_size) - 1;  	return blocks_long;  } -static struct spc_ops rd_spc_ops = { +static struct sbc_ops rd_sbc_ops = {  	.execute_rw		= rd_execute_rw,  }; -static int rd_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +rd_parse_cdb(struct se_cmd *cmd)  { -	return sbc_parse_cdb(cmd, &rd_spc_ops); +	return sbc_parse_cdb(cmd, &rd_sbc_ops);  }  static struct se_subsystem_api rd_mcp_template = {  	.name			= "rd_mcp", +	.inquiry_prod		= "RAMDISK-MCP", +	.inquiry_rev		= RD_MCP_VERSION,  	.transport_type		= TRANSPORT_PLUGIN_VHBA_VDEV,  	.attach_hba		= rd_attach_hba,  	.detach_hba		= rd_detach_hba, -	.allocate_virtdevice	= rd_allocate_virtdevice, -	.create_virtdevice	= rd_create_virtdevice, +	.alloc_device		= rd_alloc_device, +	.configure_device	= rd_configure_device,  	.free_device		= rd_free_device,  	.parse_cdb		= rd_parse_cdb, -	.check_configfs_dev_params = rd_check_configfs_dev_params,  	.set_configfs_dev_params = rd_set_configfs_dev_params,  	.show_configfs_dev_params = rd_show_configfs_dev_params, -	.get_device_rev		= rd_get_device_rev, -	.get_device_type	= rd_get_device_type, +	.get_device_type	= sbc_get_device_type,  	.get_blocks		= rd_get_blocks,  }; diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 21458125fe51..933b38b6e563 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h @@ -24,6 +24,7 @@ struct rd_dev_sg_table {  #define RDF_HAS_PAGE_COUNT	0x01  struct rd_dev { +	struct se_device dev;  	u32		rd_flags;  	/* Unique Ramdisk Device ID in Ramdisk HBA */  	u32		rd_dev_id; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index a6e27d967c7b..26a6d183ccb1 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1,10 +1,7 @@  /*   * SCSI Block Commands (SBC) parsing and emulation.   * - * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2002-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -37,7 +34,8 @@  #include "target_core_ua.h" -static int sbc_emulate_readcapacity(struct se_cmd *cmd) +static sense_reason_t +sbc_emulate_readcapacity(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev;  	unsigned long long blocks_long = dev->transport->get_blocks(dev); @@ -54,22 +52,24 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)  	buf[1] = (blocks >> 16) & 0xff;  	buf[2] = (blocks >> 8) & 0xff;  	buf[3] = blocks & 0xff; -	buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; -	buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; -	buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; -	buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; +	buf[4] = (dev->dev_attrib.block_size >> 24) & 0xff; +	buf[5] = (dev->dev_attrib.block_size >> 16) & 0xff; +	buf[6] = (dev->dev_attrib.block_size >> 8) & 0xff; +	buf[7] = dev->dev_attrib.block_size & 0xff;  	rbuf = transport_kmap_data_sg(cmd); -	if (rbuf) { -		memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); -		transport_kunmap_data_sg(cmd); -	} +	if (!rbuf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +	memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); +	transport_kunmap_data_sg(cmd);  	target_complete_cmd(cmd, GOOD);  	return 0;  } -static int sbc_emulate_readcapacity_16(struct se_cmd *cmd) +static sense_reason_t +sbc_emulate_readcapacity_16(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev;  	unsigned char *rbuf; @@ -85,28 +85,29 @@ static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)  	buf[5] = (blocks >> 16) & 0xff;  	buf[6] = (blocks >> 8) & 0xff;  	buf[7] = blocks & 0xff; -	buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; -	buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; -	buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; -	buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; +	buf[8] = (dev->dev_attrib.block_size >> 24) & 0xff; +	buf[9] = (dev->dev_attrib.block_size >> 16) & 0xff; +	buf[10] = (dev->dev_attrib.block_size >> 8) & 0xff; +	buf[11] = dev->dev_attrib.block_size & 0xff;  	/*  	 * Set Thin Provisioning Enable bit following sbc3r22 in section  	 * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.  	 */ -	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) +	if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws)  		buf[14] = 0x80;  	rbuf = transport_kmap_data_sg(cmd); -	if (rbuf) { -		memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); -		transport_kunmap_data_sg(cmd); -	} +	if (!rbuf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +	memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); +	transport_kunmap_data_sg(cmd);  	target_complete_cmd(cmd, GOOD);  	return 0;  } -int spc_get_write_same_sectors(struct se_cmd *cmd) +sector_t spc_get_write_same_sectors(struct se_cmd *cmd)  {  	u32 num_blocks; @@ -129,13 +130,8 @@ int spc_get_write_same_sectors(struct se_cmd *cmd)  }  EXPORT_SYMBOL(spc_get_write_same_sectors); -static int sbc_emulate_verify(struct se_cmd *cmd) -{ -	target_complete_cmd(cmd, GOOD); -	return 0; -} - -static int sbc_emulate_noop(struct se_cmd *cmd) +static sense_reason_t +sbc_emulate_noop(struct se_cmd *cmd)  {  	target_complete_cmd(cmd, GOOD);  	return 0; @@ -143,7 +139,7 @@ static int sbc_emulate_noop(struct se_cmd *cmd)  static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)  { -	return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors; +	return cmd->se_dev->dev_attrib.block_size * sectors;  }  static int sbc_check_valid_sectors(struct se_cmd *cmd) @@ -152,7 +148,7 @@ static int sbc_check_valid_sectors(struct se_cmd *cmd)  	unsigned long long end_lba;  	u32 sectors; -	sectors = cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size; +	sectors = cmd->data_length / dev->dev_attrib.block_size;  	end_lba = dev->transport->get_blocks(dev) + 1;  	if (cmd->t_task_lba + sectors > end_lba) { @@ -236,26 +232,37 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)  	return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;  } -static int sbc_write_same_supported(struct se_device *dev, -		unsigned char *flags) +static sense_reason_t +sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops)  { +	unsigned int sectors = spc_get_write_same_sectors(cmd); +  	if ((flags[0] & 0x04) || (flags[0] & 0x02)) {  		pr_err("WRITE_SAME PBDATA and LBDATA"  			" bits not supported for Block Discard"  			" Emulation\n"); -		return -ENOSYS; +		return TCM_UNSUPPORTED_SCSI_OPCODE; +	} +	if (sectors > cmd->se_dev->dev_attrib.max_write_same_len) { +		pr_warn("WRITE_SAME sectors: %u exceeds max_write_same_len: %u\n", +			sectors, cmd->se_dev->dev_attrib.max_write_same_len); +		return TCM_INVALID_CDB_FIELD;  	} -  	/* -	 * Currently for the emulated case we only accept -	 * tpws with the UNMAP=1 bit set. +	 * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting +	 * translated into block discard requests within backend code.  	 */ -	if (!(flags[0] & 0x08)) { -		pr_err("WRITE_SAME w/o UNMAP bit not" -			" supported for Block Discard Emulation\n"); -		return -ENOSYS; +	if (flags[0] & 0x08) { +		if (!ops->execute_write_same_unmap) +			return TCM_UNSUPPORTED_SCSI_OPCODE; + +		cmd->execute_cmd = ops->execute_write_same_unmap; +		return 0;  	} +	if (!ops->execute_write_same) +		return TCM_UNSUPPORTED_SCSI_OPCODE; +	cmd->execute_cmd = ops->execute_write_same;  	return 0;  } @@ -313,14 +320,14 @@ out:  	kfree(buf);  } -int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) +sense_reason_t +sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)  { -	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;  	struct se_device *dev = cmd->se_dev;  	unsigned char *cdb = cmd->t_task_cdb;  	unsigned int size;  	u32 sectors = 0; -	int ret; +	sense_reason_t ret;  	switch (cdb[0]) {  	case READ_6: @@ -379,9 +386,9 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  		cmd->execute_cmd = ops->execute_rw;  		break;  	case XDWRITEREAD_10: -		if ((cmd->data_direction != DMA_TO_DEVICE) || +		if (cmd->data_direction != DMA_TO_DEVICE ||  		    !(cmd->se_cmd_flags & SCF_BIDI)) -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		sectors = transport_get_sectors_10(cdb);  		cmd->t_task_lba = transport_lba_32(cdb); @@ -419,27 +426,24 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  				cmd->se_cmd_flags |= SCF_FUA;  			break;  		case WRITE_SAME_32: -			if (!ops->execute_write_same) -				goto out_unsupported_cdb; -  			sectors = transport_get_sectors_32(cdb);  			if (!sectors) {  				pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"  				       " supported\n"); -				goto out_invalid_cdb_field; +				return TCM_INVALID_CDB_FIELD;  			}  			size = sbc_get_size(cmd, 1);  			cmd->t_task_lba = get_unaligned_be64(&cdb[12]); -			if (sbc_write_same_supported(dev, &cdb[10]) < 0) -				goto out_unsupported_cdb; -			cmd->execute_cmd = ops->execute_write_same; +			ret = sbc_setup_write_same(cmd, &cdb[10], ops); +			if (ret) +				return ret;  			break;  		default:  			pr_err("VARIABLE_LENGTH_CMD service action"  				" 0x%04x not supported\n", service_action); -			goto out_unsupported_cdb; +			return TCM_UNSUPPORTED_SCSI_OPCODE;  		}  		break;  	} @@ -455,7 +459,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  		default:  			pr_err("Unsupported SA: 0x%02x\n",  				cmd->t_task_cdb[1] & 0x1f); -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		}  		size = (cdb[10] << 24) | (cdb[11] << 16) |  		       (cdb[12] << 8) | cdb[13]; @@ -463,7 +467,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  	case SYNCHRONIZE_CACHE:  	case SYNCHRONIZE_CACHE_16:  		if (!ops->execute_sync_cache) -			goto out_unsupported_cdb; +			return TCM_UNSUPPORTED_SCSI_OPCODE;  		/*  		 * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE @@ -484,42 +488,36 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  		 */  		if (cmd->t_task_lba || sectors) {  			if (sbc_check_valid_sectors(cmd) < 0) -				goto out_invalid_cdb_field; +				return TCM_INVALID_CDB_FIELD;  		}  		cmd->execute_cmd = ops->execute_sync_cache;  		break;  	case UNMAP:  		if (!ops->execute_unmap) -			goto out_unsupported_cdb; +			return TCM_UNSUPPORTED_SCSI_OPCODE;  		size = get_unaligned_be16(&cdb[7]);  		cmd->execute_cmd = ops->execute_unmap;  		break;  	case WRITE_SAME_16: -		if (!ops->execute_write_same) -			goto out_unsupported_cdb; -  		sectors = transport_get_sectors_16(cdb);  		if (!sectors) {  			pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		}  		size = sbc_get_size(cmd, 1);  		cmd->t_task_lba = get_unaligned_be64(&cdb[2]); -		if (sbc_write_same_supported(dev, &cdb[1]) < 0) -			goto out_unsupported_cdb; -		cmd->execute_cmd = ops->execute_write_same; +		ret = sbc_setup_write_same(cmd, &cdb[1], ops); +		if (ret) +			return ret;  		break;  	case WRITE_SAME: -		if (!ops->execute_write_same) -			goto out_unsupported_cdb; -  		sectors = transport_get_sectors_10(cdb);  		if (!sectors) {  			pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		}  		size = sbc_get_size(cmd, 1); @@ -529,13 +527,13 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  		 * Follow sbcr26 with WRITE_SAME (10) and check for the existence  		 * of byte 1 bit 3 UNMAP instead of original reserved field  		 */ -		if (sbc_write_same_supported(dev, &cdb[1]) < 0) -			goto out_unsupported_cdb; -		cmd->execute_cmd = ops->execute_write_same; +		ret = sbc_setup_write_same(cmd, &cdb[1], ops); +		if (ret) +			return ret;  		break;  	case VERIFY:  		size = 0; -		cmd->execute_cmd = sbc_emulate_verify; +		cmd->execute_cmd = sbc_emulate_noop;  		break;  	case REZERO_UNIT:  	case SEEK_6: @@ -557,24 +555,24 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  	/* reject any command that we don't have a handler for */  	if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd) -		goto out_unsupported_cdb; +		return TCM_UNSUPPORTED_SCSI_OPCODE;  	if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {  		unsigned long long end_lba; -		if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { +		if (sectors > dev->dev_attrib.fabric_max_sectors) {  			printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"  				" big sectors %u exceeds fabric_max_sectors:"  				" %u\n", cdb[0], sectors, -				su_dev->se_dev_attrib.fabric_max_sectors); -			goto out_invalid_cdb_field; +				dev->dev_attrib.fabric_max_sectors); +			return TCM_INVALID_CDB_FIELD;  		} -		if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { +		if (sectors > dev->dev_attrib.hw_max_sectors) {  			printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"  				" big sectors %u exceeds backend hw_max_sectors:"  				" %u\n", cdb[0], sectors, -				su_dev->se_dev_attrib.hw_max_sectors); -			goto out_invalid_cdb_field; +				dev->dev_attrib.hw_max_sectors); +			return TCM_INVALID_CDB_FIELD;  		}  		end_lba = dev->transport->get_blocks(dev) + 1; @@ -582,25 +580,18 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)  			pr_err("cmd exceeds last lba %llu "  				"(lba %llu, sectors %u)\n",  				end_lba, cmd->t_task_lba, sectors); -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		}  		size = sbc_get_size(cmd, sectors);  	} -	ret = target_cmd_size_check(cmd, size); -	if (ret < 0) -		return ret; - -	return 0; - -out_unsupported_cdb: -	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -	cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -	return -EINVAL; -out_invalid_cdb_field: -	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -	return -EINVAL; +	return target_cmd_size_check(cmd, size);  }  EXPORT_SYMBOL(sbc_parse_cdb); + +u32 sbc_get_device_type(struct se_device *dev) +{ +	return TYPE_DISK; +} +EXPORT_SYMBOL(sbc_get_device_type); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 6fd434d3d7e4..84f9e96e8ace 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1,10 +1,7 @@  /*   * SCSI Primary Commands (SPC) parsing and emulation.   * - * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2002-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -69,7 +66,8 @@ static void spc_fill_alua_data(struct se_port *port, unsigned char *buf)  	spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);  } -static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) +static sense_reason_t +spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)  {  	struct se_lun *lun = cmd->se_lun;  	struct se_device *dev = cmd->se_dev; @@ -78,7 +76,7 @@ static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)  	if (dev->transport->get_device_type(dev) == TYPE_TAPE)  		buf[1] = 0x80; -	buf[2] = dev->transport->get_device_rev(dev); +	buf[2] = 0x05; /* SPC-3 */  	/*  	 * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 @@ -95,34 +93,32 @@ static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)  	/*  	 * Enable SCCS and TPGS fields for Emulated ALUA  	 */ -	if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) -		spc_fill_alua_data(lun->lun_sep, buf); +	spc_fill_alua_data(lun->lun_sep, buf);  	buf[7] = 0x2; /* CmdQue=1 */  	snprintf(&buf[8], 8, "LIO-ORG"); -	snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); -	snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); +	snprintf(&buf[16], 16, "%s", dev->t10_wwn.model); +	snprintf(&buf[32], 4, "%s", dev->t10_wwn.revision);  	buf[4] = 31; /* Set additional length to 31 */  	return 0;  }  /* unit serial number */ -static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)  {  	struct se_device *dev = cmd->se_dev;  	u16 len = 0; -	if (dev->se_sub_dev->su_dev_flags & -			SDF_EMULATED_VPD_UNIT_SERIAL) { +	if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) {  		u32 unit_serial_len; -		unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); +		unit_serial_len = strlen(dev->t10_wwn.unit_serial);  		unit_serial_len++; /* For NULL Terminator */ -		len += sprintf(&buf[4], "%s", -			dev->se_sub_dev->t10_wwn.unit_serial); +		len += sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial);  		len++; /* Extra Byte for NULL Terminator */  		buf[3] = len;  	} @@ -132,7 +128,7 @@ static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)  static void spc_parse_naa_6h_vendor_specific(struct se_device *dev,  		unsigned char *buf)  { -	unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; +	unsigned char *p = &dev->t10_wwn.unit_serial[0];  	int cnt;  	bool next = true; @@ -164,7 +160,8 @@ static void spc_parse_naa_6h_vendor_specific(struct se_device *dev,   * Device identification VPD, for a complete list of   * DESIGNATOR TYPEs see spc4r17 Table 459.   */ -static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)  {  	struct se_device *dev = cmd->se_dev;  	struct se_lun *lun = cmd->se_lun; @@ -173,7 +170,7 @@ static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)  	struct t10_alua_lu_gp_member *lu_gp_mem;  	struct t10_alua_tg_pt_gp *tg_pt_gp;  	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; -	unsigned char *prod = &dev->se_sub_dev->t10_wwn.model[0]; +	unsigned char *prod = &dev->t10_wwn.model[0];  	u32 prod_len;  	u32 unit_serial_len, off = 0;  	u16 len = 0, id_len; @@ -188,7 +185,7 @@ static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)  	 * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial  	 * value in order to return the NAA id.  	 */ -	if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) +	if (!(dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL))  		goto check_t10_vend_desc;  	/* CODE SET == Binary */ @@ -236,14 +233,12 @@ check_t10_vend_desc:  	prod_len += strlen(prod);  	prod_len++; /* For : */ -	if (dev->se_sub_dev->su_dev_flags & -			SDF_EMULATED_VPD_UNIT_SERIAL) { -		unit_serial_len = -			strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); +	if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { +		unit_serial_len = strlen(&dev->t10_wwn.unit_serial[0]);  		unit_serial_len++; /* For NULL Terminator */  		id_len += sprintf(&buf[off+12], "%s:%s", prod, -				&dev->se_sub_dev->t10_wwn.unit_serial[0]); +				&dev->t10_wwn.unit_serial[0]);  	}  	buf[off] = 0x2; /* ASCII */  	buf[off+1] = 0x1; /* T10 Vendor ID */ @@ -298,10 +293,6 @@ check_t10_vend_desc:  		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17  		 * section 7.5.1 Table 362  		 */ -		if (dev->se_sub_dev->t10_alua.alua_type != -				SPC3_ALUA_EMULATED) -			goto check_scsi_name; -  		tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;  		if (!tg_pt_gp_mem)  			goto check_lu_gp; @@ -415,20 +406,22 @@ check_scsi_name:  }  /* Extended INQUIRY Data VPD Page */ -static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)  {  	buf[3] = 0x3c;  	/* Set HEADSUP, ORDSUP, SIMPSUP */  	buf[5] = 0x07;  	/* If WriteCache emulation is enabled, set V_SUP */ -	if (cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) +	if (cmd->se_dev->dev_attrib.emulate_write_cache > 0)  		buf[6] = 0x01;  	return 0;  }  /* Block Limits VPD page */ -static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)  {  	struct se_device *dev = cmd->se_dev;  	u32 max_sectors; @@ -439,7 +432,7 @@ static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)  	 * emulate_tpu=1 or emulate_tpws=1 we will be expect a  	 * different page length for Thin Provisioning.  	 */ -	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) +	if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws)  		have_tp = 1;  	buf[0] = dev->transport->get_device_type(dev); @@ -456,62 +449,70 @@ static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)  	/*  	 * Set MAXIMUM TRANSFER LENGTH  	 */ -	max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, -			  dev->se_sub_dev->se_dev_attrib.hw_max_sectors); +	max_sectors = min(dev->dev_attrib.fabric_max_sectors, +			  dev->dev_attrib.hw_max_sectors);  	put_unaligned_be32(max_sectors, &buf[8]);  	/*  	 * Set OPTIMAL TRANSFER LENGTH  	 */ -	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]); +	put_unaligned_be32(dev->dev_attrib.optimal_sectors, &buf[12]);  	/*  	 * Exit now if we don't support TP.  	 */  	if (!have_tp) -		return 0; +		goto max_write_same;  	/*  	 * Set MAXIMUM UNMAP LBA COUNT  	 */ -	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]); +	put_unaligned_be32(dev->dev_attrib.max_unmap_lba_count, &buf[20]);  	/*  	 * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT  	 */ -	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count, +	put_unaligned_be32(dev->dev_attrib.max_unmap_block_desc_count,  			   &buf[24]);  	/*  	 * Set OPTIMAL UNMAP GRANULARITY  	 */ -	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity, &buf[28]); +	put_unaligned_be32(dev->dev_attrib.unmap_granularity, &buf[28]);  	/*  	 * UNMAP GRANULARITY ALIGNMENT  	 */ -	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment, +	put_unaligned_be32(dev->dev_attrib.unmap_granularity_alignment,  			   &buf[32]); -	if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0) +	if (dev->dev_attrib.unmap_granularity_alignment != 0)  		buf[32] |= 0x80; /* Set the UGAVALID bit */ +	/* +	 * MAXIMUM WRITE SAME LENGTH +	 */ +max_write_same: +	put_unaligned_be64(dev->dev_attrib.max_write_same_len, &buf[36]); +  	return 0;  }  /* Block Device Characteristics VPD page */ -static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf)  {  	struct se_device *dev = cmd->se_dev;  	buf[0] = dev->transport->get_device_type(dev);  	buf[3] = 0x3c; -	buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0; +	buf[5] = dev->dev_attrib.is_nonrot ? 1 : 0;  	return 0;  }  /* Thin Provisioning VPD */ -static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)  {  	struct se_device *dev = cmd->se_dev; @@ -546,7 +547,7 @@ static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)  	 * the UNMAP command (see 5.25). A TPU bit set to zero indicates  	 * that the device server does not support the UNMAP command.  	 */ -	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu != 0) +	if (dev->dev_attrib.emulate_tpu != 0)  		buf[5] = 0x80;  	/* @@ -555,17 +556,18 @@ static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)  	 * A TPWS bit set to zero indicates that the device server does not  	 * support the use of the WRITE SAME (16) command to unmap LBAs.  	 */ -	if (dev->se_sub_dev->se_dev_attrib.emulate_tpws != 0) +	if (dev->dev_attrib.emulate_tpws != 0)  		buf[5] |= 0x40;  	return 0;  } -static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); +static sense_reason_t +spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);  static struct {  	uint8_t		page; -	int		(*emulate)(struct se_cmd *, unsigned char *); +	sense_reason_t	(*emulate)(struct se_cmd *, unsigned char *);  } evpd_handlers[] = {  	{ .page = 0x00, .emulate = spc_emulate_evpd_00 },  	{ .page = 0x80, .emulate = spc_emulate_evpd_80 }, @@ -577,7 +579,8 @@ static struct {  };  /* supported vital product data pages */ -static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)  {  	int p; @@ -586,8 +589,7 @@ static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)  	 * Registered Extended LUN WWN has been set via ConfigFS  	 * during device creation/restart.  	 */ -	if (cmd->se_dev->se_sub_dev->su_dev_flags & -			SDF_EMULATED_VPD_UNIT_SERIAL) { +	if (cmd->se_dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) {  		buf[3] = ARRAY_SIZE(evpd_handlers);  		for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)  			buf[p + 4] = evpd_handlers[p].page; @@ -596,14 +598,16 @@ static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)  	return 0;  } -static int spc_emulate_inquiry(struct se_cmd *cmd) +static sense_reason_t +spc_emulate_inquiry(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev;  	struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;  	unsigned char *rbuf;  	unsigned char *cdb = cmd->t_task_cdb;  	unsigned char buf[SE_INQUIRY_BUF]; -	int p, ret; +	sense_reason_t ret; +	int p;  	memset(buf, 0, SE_INQUIRY_BUF); @@ -616,8 +620,7 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)  		if (cdb[2]) {  			pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n",  			       cdb[2]); -			cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -			ret = -EINVAL; +			ret = TCM_INVALID_CDB_FIELD;  			goto out;  		} @@ -634,33 +637,43 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)  	}  	pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); -	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -	ret = -EINVAL; +	ret = TCM_INVALID_CDB_FIELD;  out:  	rbuf = transport_kmap_data_sg(cmd); -	if (rbuf) { -		memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); -		transport_kunmap_data_sg(cmd); -	} +	if (!rbuf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +	memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); +	transport_kunmap_data_sg(cmd);  	if (!ret)  		target_complete_cmd(cmd, GOOD);  	return ret;  } -static int spc_modesense_rwrecovery(unsigned char *p) +static int spc_modesense_rwrecovery(struct se_device *dev, u8 pc, u8 *p)  {  	p[0] = 0x01;  	p[1] = 0x0a; +	/* No changeable values for now */ +	if (pc == 1) +		goto out; + +out:  	return 12;  } -static int spc_modesense_control(struct se_device *dev, unsigned char *p) +static int spc_modesense_control(struct se_device *dev, u8 pc, u8 *p)  {  	p[0] = 0x0a;  	p[1] = 0x0a; + +	/* No changeable values for now */ +	if (pc == 1) +		goto out; +  	p[2] = 2;  	/*  	 * From spc4r23, 7.4.7 Control mode page @@ -690,7 +703,7 @@ static int spc_modesense_control(struct se_device *dev, unsigned char *p)  	 * command sequence order shall be explicitly handled by the application client  	 * through the selection of appropriate ommands and task attributes.  	 */ -	p[3] = (dev->se_sub_dev->se_dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10; +	p[3] = (dev->dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10;  	/*  	 * From spc4r17, section 7.4.6 Control mode Page  	 * @@ -720,8 +733,8 @@ static int spc_modesense_control(struct se_device *dev, unsigned char *p)  	 * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless  	 * to the number of commands completed with one of those status codes.  	 */ -	p[4] = (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 : -	       (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00; +	p[4] = (dev->dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 : +	       (dev->dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00;  	/*  	 * From spc4r17, section 7.4.6 Control mode Page  	 * @@ -734,25 +747,56 @@ static int spc_modesense_control(struct se_device *dev, unsigned char *p)  	 * which the command was received shall be completed with TASK ABORTED  	 * status (see SAM-4).  	 */ -	p[5] = (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? 0x40 : 0x00; +	p[5] = (dev->dev_attrib.emulate_tas) ? 0x40 : 0x00;  	p[8] = 0xff;  	p[9] = 0xff;  	p[11] = 30; +out:  	return 12;  } -static int spc_modesense_caching(struct se_device *dev, unsigned char *p) +static int spc_modesense_caching(struct se_device *dev, u8 pc, u8 *p)  {  	p[0] = 0x08;  	p[1] = 0x12; -	if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) + +	/* No changeable values for now */ +	if (pc == 1) +		goto out; + +	if (dev->dev_attrib.emulate_write_cache > 0)  		p[2] = 0x04; /* Write Cache Enable */  	p[12] = 0x20; /* Disabled Read Ahead */ +out:  	return 20;  } +static int spc_modesense_informational_exceptions(struct se_device *dev, u8 pc, unsigned char *p) +{ +	p[0] = 0x1c; +	p[1] = 0x0a; + +	/* No changeable values for now */ +	if (pc == 1) +		goto out; + +out: +	return 12; +} + +static struct { +	uint8_t		page; +	uint8_t		subpage; +	int		(*emulate)(struct se_device *, u8, unsigned char *); +} modesense_handlers[] = { +	{ .page = 0x01, .subpage = 0x00, .emulate = spc_modesense_rwrecovery }, +	{ .page = 0x08, .subpage = 0x00, .emulate = spc_modesense_caching }, +	{ .page = 0x0a, .subpage = 0x00, .emulate = spc_modesense_control }, +	{ .page = 0x1c, .subpage = 0x00, .emulate = spc_modesense_informational_exceptions }, +}; +  static void spc_modesense_write_protect(unsigned char *buf, int type)  {  	/* @@ -779,82 +823,224 @@ static void spc_modesense_dpofua(unsigned char *buf, int type)  	}  } -static int spc_emulate_modesense(struct se_cmd *cmd) +static int spc_modesense_blockdesc(unsigned char *buf, u64 blocks, u32 block_size) +{ +	*buf++ = 8; +	put_unaligned_be32(min(blocks, 0xffffffffull), buf); +	buf += 4; +	put_unaligned_be32(block_size, buf); +	return 9; +} + +static int spc_modesense_long_blockdesc(unsigned char *buf, u64 blocks, u32 block_size) +{ +	if (blocks <= 0xffffffff) +		return spc_modesense_blockdesc(buf + 3, blocks, block_size) + 3; + +	*buf++ = 1;		/* LONGLBA */ +	buf += 2; +	*buf++ = 16; +	put_unaligned_be64(blocks, buf); +	buf += 12; +	put_unaligned_be32(block_size, buf); + +	return 17; +} + +static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev;  	char *cdb = cmd->t_task_cdb; -	unsigned char *rbuf; +	unsigned char *buf, *map_buf;  	int type = dev->transport->get_device_type(dev);  	int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); -	u32 offset = ten ? 8 : 4; +	bool dbd = !!(cdb[1] & 0x08); +	bool llba = ten ? !!(cdb[1] & 0x10) : false; +	u8 pc = cdb[2] >> 6; +	u8 page = cdb[2] & 0x3f; +	u8 subpage = cdb[3];  	int length = 0; -	unsigned char buf[SE_MODE_PAGE_BUF]; - -	memset(buf, 0, SE_MODE_PAGE_BUF); +	int ret; +	int i; -	switch (cdb[2] & 0x3f) { -	case 0x01: -		length = spc_modesense_rwrecovery(&buf[offset]); -		break; -	case 0x08: -		length = spc_modesense_caching(dev, &buf[offset]); -		break; -	case 0x0a: -		length = spc_modesense_control(dev, &buf[offset]); -		break; -	case 0x3f: -		length = spc_modesense_rwrecovery(&buf[offset]); -		length += spc_modesense_caching(dev, &buf[offset+length]); -		length += spc_modesense_control(dev, &buf[offset+length]); -		break; -	default: -		pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", -		       cdb[2] & 0x3f, cdb[3]); -		cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; -		return -EINVAL; +	map_buf = transport_kmap_data_sg(cmd); +	if (!map_buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	/* +	 * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we +	 * know we actually allocated a full page.  Otherwise, if the +	 * data buffer is too small, allocate a temporary buffer so we +	 * don't have to worry about overruns in all our INQUIRY +	 * emulation handling. +	 */ +	if (cmd->data_length < SE_MODE_PAGE_BUF && +	    (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { +		buf = kzalloc(SE_MODE_PAGE_BUF, GFP_KERNEL); +		if (!buf) { +			transport_kunmap_data_sg(cmd); +			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		} +	} else { +		buf = map_buf;  	} -	offset += length; - -	if (ten) { -		offset -= 2; -		buf[0] = (offset >> 8) & 0xff; -		buf[1] = offset & 0xff; -		offset += 2; - -		if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || -		    (cmd->se_deve && -		    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) -			spc_modesense_write_protect(&buf[3], type); - -		if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && -		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) -			spc_modesense_dpofua(&buf[3], type); +	/* +	 * Skip over MODE DATA LENGTH + MEDIUM TYPE fields to byte 3 for +	 * MODE_SENSE_10 and byte 2 for MODE_SENSE (6). +	 */ +	length = ten ? 3 : 2; + +	/* DEVICE-SPECIFIC PARAMETER */ +	if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || +	    (cmd->se_deve && +	     (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) +		spc_modesense_write_protect(&buf[length], type); + +	if ((dev->dev_attrib.emulate_write_cache > 0) && +	    (dev->dev_attrib.emulate_fua_write > 0)) +		spc_modesense_dpofua(&buf[length], type); + +	++length; + +	/* BLOCK DESCRIPTOR */ + +	/* +	 * For now we only include a block descriptor for disk (SBC) +	 * devices; other command sets use a slightly different format. +	 */ +	if (!dbd && type == TYPE_DISK) { +		u64 blocks = dev->transport->get_blocks(dev); +		u32 block_size = dev->dev_attrib.block_size; + +		if (ten) { +			if (llba) { +				length += spc_modesense_long_blockdesc(&buf[length], +								       blocks, block_size); +			} else { +				length += 3; +				length += spc_modesense_blockdesc(&buf[length], +								  blocks, block_size); +			} +		} else { +			length += spc_modesense_blockdesc(&buf[length], blocks, +							  block_size); +		}  	} else { -		offset -= 1; -		buf[0] = offset & 0xff; -		offset += 1; - -		if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || -		    (cmd->se_deve && -		    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) -			spc_modesense_write_protect(&buf[2], type); - -		if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && -		    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) -			spc_modesense_dpofua(&buf[2], type); +		if (ten) +			length += 4; +		else +			length += 1;  	} -	rbuf = transport_kmap_data_sg(cmd); -	if (rbuf) { -		memcpy(rbuf, buf, min(offset, cmd->data_length)); -		transport_kunmap_data_sg(cmd); +	if (page == 0x3f) { +		if (subpage != 0x00 && subpage != 0xff) { +			pr_warn("MODE_SENSE: Invalid subpage code: 0x%02x\n", subpage); +			kfree(buf); +			transport_kunmap_data_sg(cmd); +			return TCM_INVALID_CDB_FIELD; +		} + +		for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) { +			/* +			 * Tricky way to say all subpage 00h for +			 * subpage==0, all subpages for subpage==0xff +			 * (and we just checked above that those are +			 * the only two possibilities). +			 */ +			if ((modesense_handlers[i].subpage & ~subpage) == 0) { +				ret = modesense_handlers[i].emulate(dev, pc, &buf[length]); +				if (!ten && length + ret >= 255) +					break; +				length += ret; +			} +		} + +		goto set_length; +	} + +	for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) +		if (modesense_handlers[i].page == page && +		    modesense_handlers[i].subpage == subpage) { +			length += modesense_handlers[i].emulate(dev, pc, &buf[length]); +			goto set_length; +		} + +	/* +	 * We don't intend to implement: +	 *  - obsolete page 03h "format parameters" (checked by Solaris) +	 */ +	if (page != 0x03) +		pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", +		       page, subpage); + +	transport_kunmap_data_sg(cmd); +	return TCM_UNKNOWN_MODE_PAGE; + +set_length: +	if (ten) +		put_unaligned_be16(length - 2, buf); +	else +		buf[0] = length - 1; + +	if (buf != map_buf) { +		memcpy(map_buf, buf, cmd->data_length); +		kfree(buf);  	} +	transport_kunmap_data_sg(cmd);  	target_complete_cmd(cmd, GOOD);  	return 0;  } -static int spc_emulate_request_sense(struct se_cmd *cmd) +static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd) +{ +	struct se_device *dev = cmd->se_dev; +	char *cdb = cmd->t_task_cdb; +	bool ten = cdb[0] == MODE_SELECT_10; +	int off = ten ? 8 : 4; +	bool pf = !!(cdb[1] & 0x10); +	u8 page, subpage; +	unsigned char *buf; +	unsigned char tbuf[SE_MODE_PAGE_BUF]; +	int length; +	int ret = 0; +	int i; + +	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +	if (!pf) { +		ret = TCM_INVALID_CDB_FIELD; +		goto out; +	} + +	page = buf[off] & 0x3f; +	subpage = buf[off] & 0x40 ? buf[off + 1] : 0; + +	for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) +		if (modesense_handlers[i].page == page && +		    modesense_handlers[i].subpage == subpage) { +			memset(tbuf, 0, SE_MODE_PAGE_BUF); +			length = modesense_handlers[i].emulate(dev, 0, tbuf); +			goto check_contents; +		} + +	ret = TCM_UNKNOWN_MODE_PAGE; +	goto out; + +check_contents: +	if (memcmp(buf + off, tbuf, length)) +		ret = TCM_INVALID_PARAMETER_LIST; + +out: +	transport_kunmap_data_sg(cmd); + +	if (!ret) +		target_complete_cmd(cmd, GOOD); +	return ret; +} + +static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd)  {  	unsigned char *cdb = cmd->t_task_cdb;  	unsigned char *rbuf; @@ -866,19 +1052,14 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)  	if (cdb[1] & 0x01) {  		pr_err("REQUEST_SENSE description emulation not"  			" supported\n"); -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -ENOSYS; +		return TCM_INVALID_CDB_FIELD;  	}  	rbuf = transport_kmap_data_sg(cmd); -	if (cmd->scsi_sense_reason != 0) { -		/* -		 * Out of memory.  We will fail with CHECK CONDITION, so -		 * we must not clear the unit attention condition. -		 */ -		target_complete_cmd(cmd, CHECK_CONDITION); -		return 0; -	} else if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { +	if (!rbuf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +	if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {  		/*  		 * CURRENT ERROR, UNIT ATTENTION  		 */ @@ -905,33 +1086,97 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)  		buf[7] = 0x0A;  	} -	if (rbuf) { -		memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); -		transport_kunmap_data_sg(cmd); +	memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); +	transport_kunmap_data_sg(cmd); + +	target_complete_cmd(cmd, GOOD); +	return 0; +} + +sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) +{ +	struct se_dev_entry *deve; +	struct se_session *sess = cmd->se_sess; +	unsigned char *buf; +	u32 lun_count = 0, offset = 8, i; + +	if (cmd->data_length < 16) { +		pr_warn("REPORT LUNS allocation length %u too small\n", +			cmd->data_length); +		return TCM_INVALID_CDB_FIELD; +	} + +	buf = transport_kmap_data_sg(cmd); +	if (!buf) +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +	/* +	 * If no struct se_session pointer is present, this struct se_cmd is +	 * coming via a target_core_mod PASSTHROUGH op, and not through +	 * a $FABRIC_MOD.  In that case, report LUN=0 only. +	 */ +	if (!sess) { +		int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); +		lun_count = 1; +		goto done; +	} + +	spin_lock_irq(&sess->se_node_acl->device_list_lock); +	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { +		deve = sess->se_node_acl->device_list[i]; +		if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) +			continue; +		/* +		 * We determine the correct LUN LIST LENGTH even once we +		 * have reached the initial allocation length. +		 * See SPC2-R20 7.19. +		 */ +		lun_count++; +		if ((offset + 8) > cmd->data_length) +			continue; + +		int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); +		offset += 8;  	} +	spin_unlock_irq(&sess->se_node_acl->device_list_lock); + +	/* +	 * See SPC3 r07, page 159. +	 */ +done: +	lun_count *= 8; +	buf[0] = ((lun_count >> 24) & 0xff); +	buf[1] = ((lun_count >> 16) & 0xff); +	buf[2] = ((lun_count >> 8) & 0xff); +	buf[3] = (lun_count & 0xff); +	transport_kunmap_data_sg(cmd);  	target_complete_cmd(cmd, GOOD);  	return 0;  } +EXPORT_SYMBOL(spc_emulate_report_luns); -static int spc_emulate_testunitready(struct se_cmd *cmd) +static sense_reason_t +spc_emulate_testunitready(struct se_cmd *cmd)  {  	target_complete_cmd(cmd, GOOD);  	return 0;  } -int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) +sense_reason_t +spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  {  	struct se_device *dev = cmd->se_dev; -	struct se_subsystem_dev *su_dev = dev->se_sub_dev;  	unsigned char *cdb = cmd->t_task_cdb;  	switch (cdb[0]) {  	case MODE_SELECT:  		*size = cdb[4]; +		cmd->execute_cmd = spc_emulate_modeselect;  		break;  	case MODE_SELECT_10:  		*size = (cdb[7] << 8) + cdb[8]; +		cmd->execute_cmd = spc_emulate_modeselect;  		break;  	case MODE_SENSE:  		*size = cdb[4]; @@ -946,14 +1191,12 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  		*size = (cdb[7] << 8) + cdb[8];  		break;  	case PERSISTENT_RESERVE_IN: -		if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) -			cmd->execute_cmd = target_scsi3_emulate_pr_in;  		*size = (cdb[7] << 8) + cdb[8]; +		cmd->execute_cmd = target_scsi3_emulate_pr_in;  		break;  	case PERSISTENT_RESERVE_OUT: -		if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) -			cmd->execute_cmd = target_scsi3_emulate_pr_out;  		*size = (cdb[7] << 8) + cdb[8]; +		cmd->execute_cmd = target_scsi3_emulate_pr_out;  		break;  	case RELEASE:  	case RELEASE_10: @@ -962,8 +1205,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  		else  			*size = cmd->data_length; -		if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) -			cmd->execute_cmd = target_scsi2_reservation_release; +		cmd->execute_cmd = target_scsi2_reservation_release;  		break;  	case RESERVE:  	case RESERVE_10: @@ -976,15 +1218,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  		else  			*size = cmd->data_length; -		/* -		 * Setup the legacy emulated handler for SPC-2 and -		 * >= SPC-3 compatible reservation handling (CRH=1) -		 * Otherwise, we assume the underlying SCSI logic is -		 * is running in SPC_PASSTHROUGH, and wants reservations -		 * emulation disabled. -		 */ -		if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) -			cmd->execute_cmd = target_scsi2_reservation_reserve; +		cmd->execute_cmd = target_scsi2_reservation_reserve;  		break;  	case REQUEST_SENSE:  		*size = cdb[4]; @@ -997,8 +1231,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  		 * Do implict HEAD_OF_QUEUE processing for INQUIRY.  		 * See spc4r17 section 5.3  		 */ -		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) -			cmd->sam_task_attr = MSG_HEAD_TAG; +		cmd->sam_task_attr = MSG_HEAD_TAG;  		cmd->execute_cmd = spc_emulate_inquiry;  		break;  	case SECURITY_PROTOCOL_IN: @@ -1020,14 +1253,13 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  		*size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];  		break;  	case REPORT_LUNS: -		cmd->execute_cmd = target_report_luns; +		cmd->execute_cmd = spc_emulate_report_luns;  		*size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];  		/*  		 * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS  		 * See spc4r17 section 5.3  		 */ -		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) -			cmd->sam_task_attr = MSG_HEAD_TAG; +		cmd->sam_task_attr = MSG_HEAD_TAG;  		break;  	case TEST_UNIT_READY:  		cmd->execute_cmd = spc_emulate_testunitready; @@ -1039,8 +1271,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  			 * MAINTENANCE_IN from SCC-2  			 * Check for emulated MI_REPORT_TARGET_PGS  			 */ -			if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && -			    su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { +			if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS) {  				cmd->execute_cmd =  					target_emulate_report_target_port_groups;  			} @@ -1058,8 +1289,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  			 * MAINTENANCE_OUT from SCC-2  			 * Check for emulated MO_SET_TARGET_PGS.  			 */ -			if (cdb[1] == MO_SET_TARGET_PGS && -			    su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { +			if (cdb[1] == MO_SET_TARGET_PGS) {  				cmd->execute_cmd =  					target_emulate_set_target_port_groups;  			} @@ -1075,9 +1305,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)  		pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"  			" 0x%02x, sending CHECK_CONDITION.\n",  			cmd->se_tfo->get_fabric_name(), cdb[0]); -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; -		return -EINVAL; +		return TCM_UNSUPPORTED_SCSI_OPCODE;  	}  	return 0; diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index cb6b0036ae95..d154ce797180 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -1,13 +1,10 @@  /*******************************************************************************   * Filename:  target_core_stat.c   * - * Copyright (c) 2011 Rising Tide Systems - * Copyright (c) 2011 Linux-iSCSI.org - *   * Modern ConfigFS group context specific statistics based on original   * target_core_mib.c code   * - * Copyright (c) 2006-2007 SBE, Inc.  All Rights Reserved. + * (c) Copyright 2006-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -80,13 +77,9 @@ static struct target_stat_scsi_dev_attribute				\  static ssize_t target_stat_scsi_dev_show_attr_inst(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_hba *hba = se_subdev->se_dev_hba; -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps); +	struct se_hba *hba = dev->se_hba;  	return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);  } @@ -95,12 +88,8 @@ DEV_STAT_SCSI_DEV_ATTR_RO(inst);  static ssize_t target_stat_scsi_dev_show_attr_indx(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);  } @@ -109,13 +98,6 @@ DEV_STAT_SCSI_DEV_ATTR_RO(indx);  static ssize_t target_stat_scsi_dev_show_attr_role(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; -  	return snprintf(page, PAGE_SIZE, "Target\n");  }  DEV_STAT_SCSI_DEV_ATTR_RO(role); @@ -123,12 +105,8 @@ DEV_STAT_SCSI_DEV_ATTR_RO(role);  static ssize_t target_stat_scsi_dev_show_attr_ports(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count);  } @@ -176,13 +154,9 @@ static struct target_stat_scsi_tgt_dev_attribute			\  static ssize_t target_stat_scsi_tgt_dev_show_attr_inst(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_hba *hba = se_subdev->se_dev_hba; -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps); +	struct se_hba *hba = dev->se_hba;  	return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);  } @@ -191,12 +165,8 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst);  static ssize_t target_stat_scsi_tgt_dev_show_attr_indx(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);  } @@ -205,13 +175,6 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx);  static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; -  	return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT);  }  DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); @@ -219,60 +182,27 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus);  static ssize_t target_stat_scsi_tgt_dev_show_attr_status(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; -	char status[16]; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps); -	if (!dev) -		return -ENODEV; - -	switch (dev->dev_status) { -	case TRANSPORT_DEVICE_ACTIVATED: -		strcpy(status, "activated"); -		break; -	case TRANSPORT_DEVICE_DEACTIVATED: -		strcpy(status, "deactivated"); -		break; -	case TRANSPORT_DEVICE_SHUTDOWN: -		strcpy(status, "shutdown"); -		break; -	case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: -	case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: -		strcpy(status, "offline"); -		break; -	default: -		sprintf(status, "unknown(%d)", dev->dev_status); -		break; -	} - -	return snprintf(page, PAGE_SIZE, "%s\n", status); +	if (dev->export_count) +		return snprintf(page, PAGE_SIZE, "activated"); +	else +		return snprintf(page, PAGE_SIZE, "deactivated");  }  DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status);  static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	int non_accessible_lus; -	if (!dev) -		return -ENODEV; - -	switch (dev->dev_status) { -	case TRANSPORT_DEVICE_ACTIVATED: +	if (dev->export_count)  		non_accessible_lus = 0; -		break; -	case TRANSPORT_DEVICE_DEACTIVATED: -	case TRANSPORT_DEVICE_SHUTDOWN: -	case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: -	case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: -	default: +	else  		non_accessible_lus = 1; -		break; -	}  	return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus);  } @@ -281,12 +211,8 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus);  static ssize_t target_stat_scsi_tgt_dev_show_attr_resets(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets);  } @@ -335,13 +261,9 @@ static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \  static ssize_t target_stat_scsi_lu_show_attr_inst(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_hba *hba = se_subdev->se_dev_hba; -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps); +	struct se_hba *hba = dev->se_hba;  	return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);  } @@ -350,12 +272,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(inst);  static ssize_t target_stat_scsi_lu_show_attr_dev(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);  } @@ -364,13 +282,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(dev);  static ssize_t target_stat_scsi_lu_show_attr_indx(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; -  	return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX);  }  DEV_STAT_SCSI_LU_ATTR_RO(indx); @@ -378,12 +289,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(indx);  static ssize_t target_stat_scsi_lu_show_attr_lun(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV;  	/* FIXME: scsiLuDefaultLun */  	return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0);  } @@ -392,35 +297,28 @@ DEV_STAT_SCSI_LU_ATTR_RO(lun);  static ssize_t target_stat_scsi_lu_show_attr_lu_name(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps); -	if (!dev) -		return -ENODEV;  	/* scsiLuWwnName */  	return snprintf(page, PAGE_SIZE, "%s\n", -			(strlen(dev->se_sub_dev->t10_wwn.unit_serial)) ? -			dev->se_sub_dev->t10_wwn.unit_serial : "None"); +			(strlen(dev->t10_wwn.unit_serial)) ? +			dev->t10_wwn.unit_serial : "None");  }  DEV_STAT_SCSI_LU_ATTR_RO(lu_name);  static ssize_t target_stat_scsi_lu_show_attr_vend(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	int i; -	char str[sizeof(dev->se_sub_dev->t10_wwn.vendor)+1]; - -	if (!dev) -		return -ENODEV; +	char str[sizeof(dev->t10_wwn.vendor)+1];  	/* scsiLuVendorId */ -	for (i = 0; i < sizeof(dev->se_sub_dev->t10_wwn.vendor); i++) -		str[i] = ISPRINT(dev->se_sub_dev->t10_wwn.vendor[i]) ? -			dev->se_sub_dev->t10_wwn.vendor[i] : ' '; +	for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++) +		str[i] = ISPRINT(dev->t10_wwn.vendor[i]) ? +			dev->t10_wwn.vendor[i] : ' ';  	str[i] = '\0';  	return snprintf(page, PAGE_SIZE, "%s\n", str);  } @@ -429,19 +327,15 @@ DEV_STAT_SCSI_LU_ATTR_RO(vend);  static ssize_t target_stat_scsi_lu_show_attr_prod(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	int i; -	char str[sizeof(dev->se_sub_dev->t10_wwn.model)+1]; - -	if (!dev) -		return -ENODEV; +	char str[sizeof(dev->t10_wwn.model)+1];  	/* scsiLuProductId */ -	for (i = 0; i < sizeof(dev->se_sub_dev->t10_wwn.vendor); i++) -		str[i] = ISPRINT(dev->se_sub_dev->t10_wwn.model[i]) ? -			dev->se_sub_dev->t10_wwn.model[i] : ' '; +	for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++) +		str[i] = ISPRINT(dev->t10_wwn.model[i]) ? +			dev->t10_wwn.model[i] : ' ';  	str[i] = '\0';  	return snprintf(page, PAGE_SIZE, "%s\n", str);  } @@ -450,19 +344,15 @@ DEV_STAT_SCSI_LU_ATTR_RO(prod);  static ssize_t target_stat_scsi_lu_show_attr_rev(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	int i; -	char str[sizeof(dev->se_sub_dev->t10_wwn.revision)+1]; - -	if (!dev) -		return -ENODEV; +	char str[sizeof(dev->t10_wwn.revision)+1];  	/* scsiLuRevisionId */ -	for (i = 0; i < sizeof(dev->se_sub_dev->t10_wwn.revision); i++) -		str[i] = ISPRINT(dev->se_sub_dev->t10_wwn.revision[i]) ? -			dev->se_sub_dev->t10_wwn.revision[i] : ' '; +	for (i = 0; i < sizeof(dev->t10_wwn.revision); i++) +		str[i] = ISPRINT(dev->t10_wwn.revision[i]) ? +			dev->t10_wwn.revision[i] : ' ';  	str[i] = '\0';  	return snprintf(page, PAGE_SIZE, "%s\n", str);  } @@ -471,12 +361,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(rev);  static ssize_t target_stat_scsi_lu_show_attr_dev_type(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuPeripheralType */  	return snprintf(page, PAGE_SIZE, "%u\n", @@ -487,30 +373,18 @@ DEV_STAT_SCSI_LU_ATTR_RO(dev_type);  static ssize_t target_stat_scsi_lu_show_attr_status(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuStatus */  	return snprintf(page, PAGE_SIZE, "%s\n", -		(dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? -		"available" : "notavailable"); +		(dev->export_count) ? "available" : "notavailable");  }  DEV_STAT_SCSI_LU_ATTR_RO(status);  static ssize_t target_stat_scsi_lu_show_attr_state_bit(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; -  	/* scsiLuState */  	return snprintf(page, PAGE_SIZE, "exposed\n");  } @@ -519,12 +393,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(state_bit);  static ssize_t target_stat_scsi_lu_show_attr_num_cmds(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuNumCommands */  	return snprintf(page, PAGE_SIZE, "%llu\n", @@ -535,12 +405,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(num_cmds);  static ssize_t target_stat_scsi_lu_show_attr_read_mbytes(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuReadMegaBytes */  	return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->read_bytes >> 20)); @@ -550,12 +416,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes);  static ssize_t target_stat_scsi_lu_show_attr_write_mbytes(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuWrittenMegaBytes */  	return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->write_bytes >> 20)); @@ -565,12 +427,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes);  static ssize_t target_stat_scsi_lu_show_attr_resets(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuInResets */  	return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); @@ -580,13 +438,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(resets);  static ssize_t target_stat_scsi_lu_show_attr_full_stat(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; -  	/* FIXME: scsiLuOutTaskSetFullStatus */  	return snprintf(page, PAGE_SIZE, "%u\n", 0);  } @@ -595,13 +446,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(full_stat);  static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; -  	/* FIXME: scsiLuHSInCommands */  	return snprintf(page, PAGE_SIZE, "%u\n", 0);  } @@ -610,12 +454,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds);  static ssize_t target_stat_scsi_lu_show_attr_creation_time(  	struct se_dev_stat_grps *sgrps, char *page)  { -	struct se_subsystem_dev *se_subdev = container_of(sgrps, -			struct se_subsystem_dev, dev_stat_grps); -	struct se_device *dev = se_subdev->se_dev_ptr; - -	if (!dev) -		return -ENODEV; +	struct se_device *dev = +		container_of(sgrps, struct se_device, dev_stat_grps);  	/* scsiLuCreationTime */  	return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - @@ -662,20 +502,20 @@ static struct config_item_type target_stat_scsi_lu_cit = {   * Called from target_core_configfs.c:target_core_make_subdev() to setup   * the target statistics groups + configfs CITs located in target_core_stat.c   */ -void target_stat_setup_dev_default_groups(struct se_subsystem_dev *se_subdev) +void target_stat_setup_dev_default_groups(struct se_device *dev)  { -	struct config_group *dev_stat_grp = &se_subdev->dev_stat_grps.stat_group; +	struct config_group *dev_stat_grp = &dev->dev_stat_grps.stat_group; -	config_group_init_type_name(&se_subdev->dev_stat_grps.scsi_dev_group, +	config_group_init_type_name(&dev->dev_stat_grps.scsi_dev_group,  			"scsi_dev", &target_stat_scsi_dev_cit); -	config_group_init_type_name(&se_subdev->dev_stat_grps.scsi_tgt_dev_group, +	config_group_init_type_name(&dev->dev_stat_grps.scsi_tgt_dev_group,  			"scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); -	config_group_init_type_name(&se_subdev->dev_stat_grps.scsi_lu_group, +	config_group_init_type_name(&dev->dev_stat_grps.scsi_lu_group,  			"scsi_lu", &target_stat_scsi_lu_cit); -	dev_stat_grp->default_groups[0] = &se_subdev->dev_stat_grps.scsi_dev_group; -	dev_stat_grp->default_groups[1] = &se_subdev->dev_stat_grps.scsi_tgt_dev_group; -	dev_stat_grp->default_groups[2] = &se_subdev->dev_stat_grps.scsi_lu_group; +	dev_stat_grp->default_groups[0] = &dev->dev_stat_grps.scsi_dev_group; +	dev_stat_grp->default_groups[1] = &dev->dev_stat_grps.scsi_tgt_dev_group; +	dev_stat_grp->default_groups[2] = &dev->dev_stat_grps.scsi_lu_group;  	dev_stat_grp->default_groups[3] = NULL;  } @@ -1161,7 +1001,7 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name(  		return -ENODEV;  	}  	tpg = sep->sep_tpg; -	wwn = &dev->se_sub_dev->t10_wwn; +	wwn = &dev->t10_wwn;  	/* scsiTransportDevName */  	ret = snprintf(page, PAGE_SIZE, "%s+%s\n",  			tpg->se_tpg_tfo->tpg_get_wwn(tpg), diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index be75c4331a92..c6e0293ffdb0 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -3,8 +3,7 @@   *   * This file contains SPC-3 task management infrastructure   * - * Copyright (c) 2009,2010 Rising Tide Systems - * Copyright (c) 2009,2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -371,7 +370,7 @@ int core_tmr_lun_reset(  	 * which the command was received shall be completed with TASK ABORTED  	 * status (see SAM-4).  	 */ -	tas = dev->se_sub_dev->se_dev_attrib.emulate_tas; +	tas = dev->dev_attrib.emulate_tas;  	/*  	 * Determine if this se_tmr is coming from a $FABRIC_MOD  	 * or struct se_device passthrough.. @@ -399,10 +398,10 @@ int core_tmr_lun_reset(  	 * LOGICAL UNIT RESET  	 */  	if (!preempt_and_abort_list && -	     (dev->dev_flags & DF_SPC2_RESERVATIONS)) { +	     (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)) {  		spin_lock(&dev->dev_reservation_lock);  		dev->dev_reserved_node_acl = NULL; -		dev->dev_flags &= ~DF_SPC2_RESERVATIONS; +		dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS;  		spin_unlock(&dev->dev_reservation_lock);  		pr_debug("LUN_RESET: SCSI-2 Released reservation\n");  	} diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index a531fe282b1e..5192ac0337f7 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -3,10 +3,7 @@   *   * This file contains generic Target Portal Group related functions.   * - * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2002-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -619,6 +616,29 @@ int core_tpg_set_initiator_node_queue_depth(  }  EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth); +/*	core_tpg_set_initiator_node_tag(): + * + *	Initiator nodeacl tags are not used internally, but may be used by + *	userspace to emulate aliases or groups. + *	Returns length of newly-set tag or -EINVAL. + */ +int core_tpg_set_initiator_node_tag( +	struct se_portal_group *tpg, +	struct se_node_acl *acl, +	const char *new_tag) +{ +	if (strlen(new_tag) >= MAX_ACL_TAG_SIZE) +		return -EINVAL; + +	if (!strncmp("NULL", new_tag, 4)) { +		acl->acl_tag[0] = '\0'; +		return 0; +	} + +	return snprintf(acl->acl_tag, MAX_ACL_TAG_SIZE, "%s", new_tag); +} +EXPORT_SYMBOL(core_tpg_set_initiator_node_tag); +  static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)  {  	/* Set in core_dev_setup_virtual_lun0() */ @@ -672,6 +692,7 @@ int core_tpg_register(  	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {  		lun = se_tpg->tpg_lun_list[i];  		lun->unpacked_lun = i; +		lun->lun_link_magic = SE_LUN_LINK_MAGIC;  		lun->lun_status = TRANSPORT_LUN_STATUS_FREE;  		atomic_set(&lun->lun_acl_count, 0);  		init_completion(&lun->lun_shutdown_comp); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index dcecbfb17243..c23c76ccef65 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3,10 +3,7 @@   *   * This file contains the Generic Target Engine Core.   * - * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2002-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -70,7 +67,6 @@ static void transport_handle_queue_full(struct se_cmd *cmd,  static int transport_generic_get_mem(struct se_cmd *cmd);  static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);  static void transport_put_cmd(struct se_cmd *cmd); -static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);  static void target_complete_ok_work(struct work_struct *work);  int init_se_kmem_caches(void) @@ -297,7 +293,7 @@ void transport_register_session(  }  EXPORT_SYMBOL(transport_register_session); -void target_release_session(struct kref *kref) +static void target_release_session(struct kref *kref)  {  	struct se_session *se_sess = container_of(kref,  			struct se_session, sess_kref); @@ -558,7 +554,8 @@ static void target_complete_failure_work(struct work_struct *work)  {  	struct se_cmd *cmd = container_of(work, struct se_cmd, work); -	transport_generic_request_failure(cmd); +	transport_generic_request_failure(cmd, +			TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);  }  /* @@ -626,7 +623,6 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)  		complete(&cmd->t_transport_stop_comp);  		return;  	} else if (cmd->transport_state & CMD_T_FAILED) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  		INIT_WORK(&cmd->work, target_complete_failure_work);  	} else {  		INIT_WORK(&cmd->work, target_complete_ok_work); @@ -659,7 +655,7 @@ static void target_add_to_state_list(struct se_cmd *cmd)  static void transport_write_pending_qf(struct se_cmd *cmd);  static void transport_complete_qf(struct se_cmd *cmd); -static void target_qf_do_work(struct work_struct *work) +void target_qf_do_work(struct work_struct *work)  {  	struct se_device *dev = container_of(work, struct se_device,  					qf_work_queue); @@ -712,29 +708,15 @@ void transport_dump_dev_state(  	int *bl)  {  	*bl += sprintf(b + *bl, "Status: "); -	switch (dev->dev_status) { -	case TRANSPORT_DEVICE_ACTIVATED: +	if (dev->export_count)  		*bl += sprintf(b + *bl, "ACTIVATED"); -		break; -	case TRANSPORT_DEVICE_DEACTIVATED: +	else  		*bl += sprintf(b + *bl, "DEACTIVATED"); -		break; -	case TRANSPORT_DEVICE_SHUTDOWN: -		*bl += sprintf(b + *bl, "SHUTDOWN"); -		break; -	case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: -	case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: -		*bl += sprintf(b + *bl, "OFFLINE"); -		break; -	default: -		*bl += sprintf(b + *bl, "UNKNOWN=%d", dev->dev_status); -		break; -	}  	*bl += sprintf(b + *bl, "  Max Queue Depth: %d", dev->queue_depth);  	*bl += sprintf(b + *bl, "  SectorSize: %u  HwMaxSectors: %u\n", -		dev->se_sub_dev->se_dev_attrib.block_size, -		dev->se_sub_dev->se_dev_attrib.hw_max_sectors); +		dev->dev_attrib.block_size, +		dev->dev_attrib.hw_max_sectors);  	*bl += sprintf(b + *bl, "        ");  } @@ -991,186 +973,8 @@ transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)  }  EXPORT_SYMBOL(transport_set_vpd_ident); -static void core_setup_task_attr_emulation(struct se_device *dev) -{ -	/* -	 * If this device is from Target_Core_Mod/pSCSI, disable the -	 * SAM Task Attribute emulation. -	 * -	 * This is currently not available in upsream Linux/SCSI Target -	 * mode code, and is assumed to be disabled while using TCM/pSCSI. -	 */ -	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { -		dev->dev_task_attr_type = SAM_TASK_ATTR_PASSTHROUGH; -		return; -	} - -	dev->dev_task_attr_type = SAM_TASK_ATTR_EMULATED; -	pr_debug("%s: Using SAM_TASK_ATTR_EMULATED for SPC: 0x%02x" -		" device\n", dev->transport->name, -		dev->transport->get_device_rev(dev)); -} - -static void scsi_dump_inquiry(struct se_device *dev) -{ -	struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; -	char buf[17]; -	int i, device_type; -	/* -	 * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer -	 */ -	for (i = 0; i < 8; i++) -		if (wwn->vendor[i] >= 0x20) -			buf[i] = wwn->vendor[i]; -		else -			buf[i] = ' '; -	buf[i] = '\0'; -	pr_debug("  Vendor: %s\n", buf); - -	for (i = 0; i < 16; i++) -		if (wwn->model[i] >= 0x20) -			buf[i] = wwn->model[i]; -		else -			buf[i] = ' '; -	buf[i] = '\0'; -	pr_debug("  Model: %s\n", buf); - -	for (i = 0; i < 4; i++) -		if (wwn->revision[i] >= 0x20) -			buf[i] = wwn->revision[i]; -		else -			buf[i] = ' '; -	buf[i] = '\0'; -	pr_debug("  Revision: %s\n", buf); - -	device_type = dev->transport->get_device_type(dev); -	pr_debug("  Type:   %s ", scsi_device_type(device_type)); -	pr_debug("                 ANSI SCSI revision: %02x\n", -				dev->transport->get_device_rev(dev)); -} - -struct se_device *transport_add_device_to_core_hba( -	struct se_hba *hba, -	struct se_subsystem_api *transport, -	struct se_subsystem_dev *se_dev, -	u32 device_flags, -	void *transport_dev, -	struct se_dev_limits *dev_limits, -	const char *inquiry_prod, -	const char *inquiry_rev) -{ -	int force_pt; -	struct se_device  *dev; - -	dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); -	if (!dev) { -		pr_err("Unable to allocate memory for se_dev_t\n"); -		return NULL; -	} - -	dev->dev_flags		= device_flags; -	dev->dev_status		|= TRANSPORT_DEVICE_DEACTIVATED; -	dev->dev_ptr		= transport_dev; -	dev->se_hba		= hba; -	dev->se_sub_dev		= se_dev; -	dev->transport		= transport; -	INIT_LIST_HEAD(&dev->dev_list); -	INIT_LIST_HEAD(&dev->dev_sep_list); -	INIT_LIST_HEAD(&dev->dev_tmr_list); -	INIT_LIST_HEAD(&dev->delayed_cmd_list); -	INIT_LIST_HEAD(&dev->state_list); -	INIT_LIST_HEAD(&dev->qf_cmd_list); -	spin_lock_init(&dev->execute_task_lock); -	spin_lock_init(&dev->delayed_cmd_lock); -	spin_lock_init(&dev->dev_reservation_lock); -	spin_lock_init(&dev->dev_status_lock); -	spin_lock_init(&dev->se_port_lock); -	spin_lock_init(&dev->se_tmr_lock); -	spin_lock_init(&dev->qf_cmd_lock); -	atomic_set(&dev->dev_ordered_id, 0); - -	se_dev_set_default_attribs(dev, dev_limits); - -	dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); -	dev->creation_time = get_jiffies_64(); -	spin_lock_init(&dev->stats_lock); - -	spin_lock(&hba->device_lock); -	list_add_tail(&dev->dev_list, &hba->hba_dev_list); -	hba->dev_count++; -	spin_unlock(&hba->device_lock); -	/* -	 * Setup the SAM Task Attribute emulation for struct se_device -	 */ -	core_setup_task_attr_emulation(dev); -	/* -	 * Force PR and ALUA passthrough emulation with internal object use. -	 */ -	force_pt = (hba->hba_flags & HBA_FLAGS_INTERNAL_USE); -	/* -	 * Setup the Reservations infrastructure for struct se_device -	 */ -	core_setup_reservations(dev, force_pt); -	/* -	 * Setup the Asymmetric Logical Unit Assignment for struct se_device -	 */ -	if (core_setup_alua(dev, force_pt) < 0) -		goto err_dev_list; - -	/* -	 * Startup the struct se_device processing thread -	 */ -	dev->tmr_wq = alloc_workqueue("tmr-%s", WQ_MEM_RECLAIM | WQ_UNBOUND, 1, -				      dev->transport->name); -	if (!dev->tmr_wq) { -		pr_err("Unable to create tmr workqueue for %s\n", -			dev->transport->name); -		goto err_dev_list; -	} -	/* -	 * Setup work_queue for QUEUE_FULL -	 */ -	INIT_WORK(&dev->qf_work_queue, target_qf_do_work); -	/* -	 * Preload the initial INQUIRY const values if we are doing -	 * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI -	 * passthrough because this is being provided by the backend LLD. -	 * This is required so that transport_get_inquiry() copies these -	 * originals once back into DEV_T10_WWN(dev) for the virtual device -	 * setup. -	 */ -	if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { -		if (!inquiry_prod || !inquiry_rev) { -			pr_err("All non TCM/pSCSI plugins require" -				" INQUIRY consts\n"); -			goto err_wq; -		} - -		strncpy(&dev->se_sub_dev->t10_wwn.vendor[0], "LIO-ORG", 8); -		strncpy(&dev->se_sub_dev->t10_wwn.model[0], inquiry_prod, 16); -		strncpy(&dev->se_sub_dev->t10_wwn.revision[0], inquiry_rev, 4); -	} -	scsi_dump_inquiry(dev); - -	return dev; - -err_wq: -	destroy_workqueue(dev->tmr_wq); -err_dev_list: -	spin_lock(&hba->device_lock); -	list_del(&dev->dev_list); -	hba->dev_count--; -	spin_unlock(&hba->device_lock); - -	se_release_vpd_for_dev(dev); - -	kfree(dev); - -	return NULL; -} -EXPORT_SYMBOL(transport_add_device_to_core_hba); - -int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) +sense_reason_t +target_cmd_size_check(struct se_cmd *cmd, unsigned int size)  {  	struct se_device *dev = cmd->se_dev; @@ -1185,18 +989,18 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)  		if (cmd->data_direction == DMA_TO_DEVICE) {  			pr_err("Rejecting underflow/overflow"  					" WRITE data\n"); -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		}  		/*  		 * Reject READ_* or WRITE_* with overflow/underflow for  		 * type SCF_SCSI_DATA_CDB.  		 */ -		if (dev->se_sub_dev->se_dev_attrib.block_size != 512)  { +		if (dev->dev_attrib.block_size != 512)  {  			pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"  				" CDB on non 512-byte sector setup subsystem"  				" plugin: %s\n", dev->transport->name);  			/* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ -			goto out_invalid_cdb_field; +			return TCM_INVALID_CDB_FIELD;  		}  		/*  		 * For the overflow case keep the existing fabric provided @@ -1216,10 +1020,6 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)  	return 0; -out_invalid_cdb_field: -	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -	return -EINVAL;  }  /* @@ -1259,45 +1059,41 @@ void transport_init_se_cmd(  }  EXPORT_SYMBOL(transport_init_se_cmd); -static int transport_check_alloc_task_attr(struct se_cmd *cmd) +static sense_reason_t +transport_check_alloc_task_attr(struct se_cmd *cmd)  { +	struct se_device *dev = cmd->se_dev; +  	/*  	 * Check if SAM Task Attribute emulation is enabled for this  	 * struct se_device storage object  	 */ -	if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)  		return 0;  	if (cmd->sam_task_attr == MSG_ACA_TAG) {  		pr_debug("SAM Task Attribute ACA"  			" emulation is not supported\n"); -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	/*  	 * Used to determine when ORDERED commands should go from  	 * Dormant to Active status.  	 */ -	cmd->se_ordered_id = atomic_inc_return(&cmd->se_dev->dev_ordered_id); +	cmd->se_ordered_id = atomic_inc_return(&dev->dev_ordered_id);  	smp_mb__after_atomic_inc();  	pr_debug("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n",  			cmd->se_ordered_id, cmd->sam_task_attr, -			cmd->se_dev->transport->name); +			dev->transport->name);  	return 0;  } -/*	target_setup_cmd_from_cdb(): - * - *	Called from fabric RX Thread. - */ -int target_setup_cmd_from_cdb( -	struct se_cmd *cmd, -	unsigned char *cdb) +sense_reason_t +target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)  { -	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; -	u32 pr_reg_type = 0; -	u8 alua_ascq = 0; +	struct se_device *dev = cmd->se_dev;  	unsigned long flags; -	int ret; +	sense_reason_t ret;  	/*  	 * Ensure that the received CDB is less than the max (252 + 8) bytes @@ -1307,9 +1103,7 @@ int target_setup_cmd_from_cdb(  		pr_err("Received SCSI CDB with command_size: %d that"  			" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",  			scsi_command_size(cdb), SCSI_MAX_VARLEN_CDB_SIZE); -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; +		return TCM_INVALID_CDB_FIELD;  	}  	/*  	 * If the received CDB is larger than TCM_MAX_COMMAND_SIZE, @@ -1324,10 +1118,7 @@ int target_setup_cmd_from_cdb(  				" %u > sizeof(cmd->__t_task_cdb): %lu ops\n",  				scsi_command_size(cdb),  				(unsigned long)sizeof(cmd->__t_task_cdb)); -			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -			cmd->scsi_sense_reason = -					TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -			return -ENOMEM; +			return TCM_OUT_OF_RESOURCES;  		}  	} else  		cmd->t_task_cdb = &cmd->__t_task_cdb[0]; @@ -1339,70 +1130,30 @@ int target_setup_cmd_from_cdb(  	/*  	 * Check for an existing UNIT ATTENTION condition  	 */ -	if (core_scsi3_ua_check(cmd, cdb) < 0) { -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; -		return -EINVAL; -	} +	ret = target_scsi3_ua_check(cmd); +	if (ret) +		return ret; -	ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq); -	if (ret != 0) { -		/* -		 * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; -		 * The ALUA additional sense code qualifier (ASCQ) is determined -		 * by the ALUA primary or secondary access state.. -		 */ -		if (ret > 0) { -			pr_debug("[%s]: ALUA TG Port not available, " -				"SenseKey: NOT_READY, ASC/ASCQ: " -				"0x04/0x%02x\n", -				cmd->se_tfo->get_fabric_name(), alua_ascq); - -			transport_set_sense_codes(cmd, 0x04, alua_ascq); -			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -			cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; -			return -EINVAL; -		} -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; -	} +	ret = target_alua_state_check(cmd); +	if (ret) +		return ret; -	/* -	 * Check status for SPC-3 Persistent Reservations -	 */ -	if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type)) { -		if (su_dev->t10_pr.pr_ops.t10_seq_non_holder( -					cmd, cdb, pr_reg_type) != 0) { -			cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -			cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; -			cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; -			cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; -			return -EBUSY; -		} -		/* -		 * This means the CDB is allowed for the SCSI Initiator port -		 * when said port is *NOT* holding the legacy SPC-2 or -		 * SPC-3 Persistent Reservation. -		 */ -	} +	ret = target_check_reservation(cmd); +	if (ret) +		return ret; -	ret = cmd->se_dev->transport->parse_cdb(cmd); -	if (ret < 0) +	ret = dev->transport->parse_cdb(cmd); +	if (ret) +		return ret; + +	ret = transport_check_alloc_task_attr(cmd); +	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); -	/* -	 * Check for SAM Task Attribute Emulation -	 */ -	if (transport_check_alloc_task_attr(cmd) < 0) { -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; -	}  	spin_lock(&cmd->se_lun->lun_sep_lock);  	if (cmd->se_lun->lun_sep)  		cmd->se_lun->lun_sep->sep_stats.cmd_pdus++; @@ -1418,7 +1169,7 @@ EXPORT_SYMBOL(target_setup_cmd_from_cdb);  int transport_handle_cdb_direct(  	struct se_cmd *cmd)  { -	int ret; +	sense_reason_t ret;  	if (!cmd->se_lun) {  		dump_stack(); @@ -1448,13 +1199,41 @@ int transport_handle_cdb_direct(  	 * and call transport_generic_request_failure() if necessary..  	 */  	ret = transport_generic_new_cmd(cmd); -	if (ret < 0) -		transport_generic_request_failure(cmd); - +	if (ret) +		transport_generic_request_failure(cmd, ret);  	return 0;  }  EXPORT_SYMBOL(transport_handle_cdb_direct); +static sense_reason_t +transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, +		u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count) +{ +	if (!sgl || !sgl_count) +		return 0; + +	/* +	 * Reject SCSI data overflow with map_mem_to_cmd() as incoming +	 * scatterlists already have been set to follow what the fabric +	 * passes for the original expected data transfer length. +	 */ +	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { +		pr_warn("Rejecting SCSI DATA overflow for fabric using" +			" SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); +		return TCM_INVALID_CDB_FIELD; +	} + +	cmd->t_data_sg = sgl; +	cmd->t_data_nents = sgl_count; + +	if (sgl_bidi && sgl_bidi_count) { +		cmd->t_bidi_data_sg = sgl_bidi; +		cmd->t_bidi_data_nents = sgl_bidi_count; +	} +	cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; +	return 0; +} +  /*   * target_submit_cmd_map_sgls - lookup unpacked lun and submit uninitialized   * 			 se_cmd + use pre-allocated SGL memory. @@ -1487,7 +1266,8 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess  		struct scatterlist *sgl_bidi, u32 sgl_bidi_count)  {  	struct se_portal_group *se_tpg; -	int rc; +	sense_reason_t rc; +	int ret;  	se_tpg = se_sess->se_tpg;  	BUG_ON(!se_tpg); @@ -1508,9 +1288,9 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess  	 * for fabrics using TARGET_SCF_ACK_KREF that expect a second  	 * kref_put() to happen during fabric packet acknowledgement.  	 */ -	rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); -	if (rc) -		return rc; +	ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); +	if (ret) +		return ret;  	/*  	 * Signal bidirectional data payloads to target-core  	 */ @@ -1519,16 +1299,16 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess  	/*  	 * Locate se_lun pointer and attach it to struct se_cmd  	 */ -	if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0) { -		transport_send_check_condition_and_sense(se_cmd, -				se_cmd->scsi_sense_reason, 0); +	rc = transport_lookup_cmd_lun(se_cmd, unpacked_lun); +	if (rc) { +		transport_send_check_condition_and_sense(se_cmd, rc, 0);  		target_put_sess_cmd(se_sess, se_cmd);  		return 0;  	}  	rc = target_setup_cmd_from_cdb(se_cmd, cdb);  	if (rc != 0) { -		transport_generic_request_failure(se_cmd); +		transport_generic_request_failure(se_cmd, rc);  		return 0;  	}  	/* @@ -1563,7 +1343,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess  		rc = transport_generic_map_mem_to_cmd(se_cmd, sgl, sgl_count,  				sgl_bidi, sgl_bidi_count);  		if (rc != 0) { -			transport_generic_request_failure(se_cmd); +			transport_generic_request_failure(se_cmd, rc);  			return 0;  		}  	} @@ -1709,16 +1489,17 @@ bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)  /*   * Handle SAM-esque emulation for generic transport request failures.   */ -void transport_generic_request_failure(struct se_cmd *cmd) +void transport_generic_request_failure(struct se_cmd *cmd, +		sense_reason_t sense_reason)  {  	int ret = 0;  	pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x"  		" CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd),  		cmd->t_task_cdb[0]); -	pr_debug("-----[ i_state: %d t_state: %d scsi_sense_reason: %d\n", +	pr_debug("-----[ i_state: %d t_state: %d sense_reason: %d\n",  		cmd->se_tfo->get_cmd_state(cmd), -		cmd->t_state, cmd->scsi_sense_reason); +		cmd->t_state, sense_reason);  	pr_debug("-----[ CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n",  		(cmd->transport_state & CMD_T_ACTIVE) != 0,  		(cmd->transport_state & CMD_T_STOP) != 0, @@ -1727,10 +1508,9 @@ void transport_generic_request_failure(struct se_cmd *cmd)  	/*  	 * For SAM Task Attribute emulation for failed struct se_cmd  	 */ -	if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) -		transport_complete_task_attr(cmd); +	transport_complete_task_attr(cmd); -	switch (cmd->scsi_sense_reason) { +	switch (sense_reason) {  	case TCM_NON_EXISTENT_LUN:  	case TCM_UNSUPPORTED_SCSI_OPCODE:  	case TCM_INVALID_CDB_FIELD: @@ -1743,6 +1523,9 @@ void transport_generic_request_failure(struct se_cmd *cmd)  	case TCM_CHECK_CONDITION_UNIT_ATTENTION:  	case TCM_CHECK_CONDITION_NOT_READY:  		break; +	case TCM_OUT_OF_RESOURCES: +		sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		break;  	case TCM_RESERVATION_CONFLICT:  		/*  		 * No SENSE Data payload for this case, set SCSI Status @@ -1759,7 +1542,7 @@ void transport_generic_request_failure(struct se_cmd *cmd)  		 * See spc4r17, section 7.4.6 Control Mode Page, Table 349  		 */  		if (cmd->se_sess && -		    cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) +		    cmd->se_dev->dev_attrib.emulate_ua_intlck_ctrl == 2)  			core_scsi3_ua_allocate(cmd->se_sess->se_node_acl,  				cmd->orig_fe_lun, 0x2C,  				ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); @@ -1770,13 +1553,12 @@ void transport_generic_request_failure(struct se_cmd *cmd)  		goto check_stop;  	default:  		pr_err("Unknown transport error for CDB 0x%02x: %d\n", -			cmd->t_task_cdb[0], cmd->scsi_sense_reason); -		cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; +			cmd->t_task_cdb[0], sense_reason); +		sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;  		break;  	} -	ret = transport_send_check_condition_and_sense(cmd, -			cmd->scsi_sense_reason, 0); +	ret = transport_send_check_condition_and_sense(cmd, sense_reason, 0);  	if (ret == -EAGAIN || ret == -ENOMEM)  		goto queue_full; @@ -1794,69 +1576,30 @@ EXPORT_SYMBOL(transport_generic_request_failure);  static void __target_execute_cmd(struct se_cmd *cmd)  { -	int error = 0; +	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) -		error = cmd->execute_cmd(cmd); +	if (cmd->execute_cmd) { +		ret = cmd->execute_cmd(cmd); +		if (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 (error) { -		spin_lock_irq(&cmd->t_state_lock); -		cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT); -		spin_unlock_irq(&cmd->t_state_lock); - -		transport_generic_request_failure(cmd); +			transport_generic_request_failure(cmd, ret); +		}  	}  } -void target_execute_cmd(struct se_cmd *cmd) +static bool target_handle_task_attr(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; -	/* -	 * If the received CDB has aleady been aborted stop processing it here. -	 */ -	if (transport_check_aborted_status(cmd, 1)) { -		complete(&cmd->t_transport_stop_comp); -		return; -	} - -	/* -	 * Determine if IOCTL context caller in requesting the stopping of this -	 * command for LUN shutdown purposes. -	 */ -	spin_lock_irq(&cmd->t_state_lock); -	if (cmd->transport_state & CMD_T_LUN_STOP) { -		pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n", -			__func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - -		cmd->transport_state &= ~CMD_T_ACTIVE; -		spin_unlock_irq(&cmd->t_state_lock); -		complete(&cmd->transport_lun_stop_comp); -		return; -	} -	/* -	 * Determine if frontend context caller is requesting the stopping of -	 * this command for frontend exceptions. -	 */ -	if (cmd->transport_state & CMD_T_STOP) { -		pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", -			__func__, __LINE__, -			cmd->se_tfo->get_task_tag(cmd)); - -		spin_unlock_irq(&cmd->t_state_lock); -		complete(&cmd->t_transport_stop_comp); -		return; -	} - -	cmd->t_state = TRANSPORT_PROCESSING; -	spin_unlock_irq(&cmd->t_state_lock); - -	if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) -		goto execute; +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) +		return false;  	/*  	 * Check for the existence of HEAD_OF_QUEUE, and if true return 1 @@ -1867,7 +1610,7 @@ void target_execute_cmd(struct se_cmd *cmd)  		pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, "  			 "se_ordered_id: %u\n",  			 cmd->t_task_cdb[0], cmd->se_ordered_id); -		goto execute; +		return false;  	case MSG_ORDERED_TAG:  		atomic_inc(&dev->dev_ordered_sync);  		smp_mb__after_atomic_inc(); @@ -1881,7 +1624,7 @@ void target_execute_cmd(struct se_cmd *cmd)  		 * exist that need to be completed first.  		 */  		if (!atomic_read(&dev->simple_cmds)) -			goto execute; +			return false;  		break;  	default:  		/* @@ -1892,23 +1635,63 @@ void target_execute_cmd(struct se_cmd *cmd)  		break;  	} -	if (atomic_read(&dev->dev_ordered_sync) != 0) { -		spin_lock(&dev->delayed_cmd_lock); -		list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); -		spin_unlock(&dev->delayed_cmd_lock); +	if (atomic_read(&dev->dev_ordered_sync) == 0) +		return false; -		pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to" -			" delayed CMD list, se_ordered_id: %u\n", -			cmd->t_task_cdb[0], cmd->sam_task_attr, -			cmd->se_ordered_id); +	spin_lock(&dev->delayed_cmd_lock); +	list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); +	spin_unlock(&dev->delayed_cmd_lock); + +	pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to" +		" delayed CMD list, se_ordered_id: %u\n", +		cmd->t_task_cdb[0], cmd->sam_task_attr, +		cmd->se_ordered_id); +	return true; +} + +void target_execute_cmd(struct se_cmd *cmd) +{ +	/* +	 * If the received CDB has aleady been aborted stop processing it here. +	 */ +	if (transport_check_aborted_status(cmd, 1)) { +		complete(&cmd->transport_lun_stop_comp);  		return;  	} -execute:  	/* -	 * Otherwise, no ORDERED task attributes exist.. +	 * Determine if IOCTL context caller in requesting the stopping of this +	 * command for LUN shutdown purposes.  	 */ -	__target_execute_cmd(cmd); +	spin_lock_irq(&cmd->t_state_lock); +	if (cmd->transport_state & CMD_T_LUN_STOP) { +		pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n", +			__func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); + +		cmd->transport_state &= ~CMD_T_ACTIVE; +		spin_unlock_irq(&cmd->t_state_lock); +		complete(&cmd->transport_lun_stop_comp); +		return; +	} +	/* +	 * Determine if frontend context caller is requesting the stopping of +	 * this command for frontend exceptions. +	 */ +	if (cmd->transport_state & CMD_T_STOP) { +		pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", +			__func__, __LINE__, +			cmd->se_tfo->get_task_tag(cmd)); + +		spin_unlock_irq(&cmd->t_state_lock); +		complete(&cmd->t_transport_stop_comp); +		return; +	} + +	cmd->t_state = TRANSPORT_PROCESSING; +	spin_unlock_irq(&cmd->t_state_lock); + +	if (!target_handle_task_attr(cmd)) +		__target_execute_cmd(cmd);  }  EXPORT_SYMBOL(target_execute_cmd); @@ -1947,6 +1730,9 @@ static void transport_complete_task_attr(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; +	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) +		return; +  	if (cmd->sam_task_attr == MSG_SIMPLE_TAG) {  		atomic_dec(&dev->simple_cmds);  		smp_mb__after_atomic_dec(); @@ -1975,8 +1761,7 @@ static void transport_complete_qf(struct se_cmd *cmd)  {  	int ret = 0; -	if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) -		transport_complete_task_attr(cmd); +	transport_complete_task_attr(cmd);  	if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {  		ret = cmd->se_tfo->queue_status(cmd); @@ -2034,8 +1819,8 @@ static void target_complete_ok_work(struct work_struct *work)  	 * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task  	 * Attribute.  	 */ -	if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) -		transport_complete_task_attr(cmd); +	transport_complete_task_attr(cmd); +  	/*  	 * Check to schedule QUEUE_FULL work, or execute an existing  	 * cmd->transport_qf_callback() @@ -2183,9 +1968,10 @@ static void 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)) { -		if (!atomic_dec_and_test(&cmd->t_fe_count)) -			goto out_busy; +	if (atomic_read(&cmd->t_fe_count) && +	    !atomic_dec_and_test(&cmd->t_fe_count)) { +		spin_unlock_irqrestore(&cmd->t_state_lock, flags); +		return;  	}  	if (cmd->transport_state & CMD_T_DEV_ACTIVE) { @@ -2197,56 +1983,7 @@ static void transport_put_cmd(struct se_cmd *cmd)  	transport_free_pages(cmd);  	transport_release_cmd(cmd);  	return; -out_busy: -	spin_unlock_irqrestore(&cmd->t_state_lock, flags); -} - -/* - * transport_generic_map_mem_to_cmd - Use fabric-alloced pages instead of - * allocating in the core. - * @cmd:  Associated se_cmd descriptor - * @mem:  SGL style memory for TCM WRITE / READ - * @sg_mem_num: Number of SGL elements - * @mem_bidi_in: SGL style memory for TCM BIDI READ - * @sg_mem_bidi_num: Number of BIDI READ SGL elements - * - * Return: nonzero return cmd was rejected for -ENOMEM or inproper usage - * of parameters. - */ -int transport_generic_map_mem_to_cmd( -	struct se_cmd *cmd, -	struct scatterlist *sgl, -	u32 sgl_count, -	struct scatterlist *sgl_bidi, -	u32 sgl_bidi_count) -{ -	if (!sgl || !sgl_count) -		return 0; - -	/* -	 * Reject SCSI data overflow with map_mem_to_cmd() as incoming -	 * scatterlists already have been set to follow what the fabric -	 * passes for the original expected data transfer length. -	 */ -	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { -		pr_warn("Rejecting SCSI DATA overflow for fabric using" -			" SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); -		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; -		return -EINVAL; -	} - -	cmd->t_data_sg = sgl; -	cmd->t_data_nents = sgl_count; - -	if (sgl_bidi && sgl_bidi_count) { -		cmd->t_bidi_data_sg = sgl_bidi; -		cmd->t_bidi_data_nents = sgl_bidi_count; -	} -	cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; -	return 0;  } -EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);  void *transport_kmap_data_sg(struct se_cmd *cmd)  { @@ -2268,10 +2005,8 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)  	/* >1 page. use vmap */  	pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); -	if (!pages) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	if (!pages)  		return NULL; -	}  	/* convert sg[] to pages[] */  	for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { @@ -2280,10 +2015,8 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)  	cmd->t_data_vmap = vmap(pages, cmd->t_data_nents,  VM_MAP, PAGE_KERNEL);  	kfree(pages); -	if (!cmd->t_data_vmap) { -		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	if (!cmd->t_data_vmap)  		return NULL; -	}  	return cmd->t_data_vmap + cmd->t_data_sg[0].offset;  } @@ -2349,7 +2082,8 @@ out:   * might not have the payload yet, so notify the fabric via a call to   * ->write_pending instead. Otherwise place it on the execution queue.   */ -int transport_generic_new_cmd(struct se_cmd *cmd) +sense_reason_t +transport_generic_new_cmd(struct se_cmd *cmd)  {  	int ret = 0; @@ -2362,7 +2096,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd)  	    cmd->data_length) {  		ret = transport_generic_get_mem(cmd);  		if (ret < 0) -			goto out_fail; +			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	}  	atomic_inc(&cmd->t_fe_count); @@ -2388,14 +2122,11 @@ int transport_generic_new_cmd(struct se_cmd *cmd)  	if (ret == -EAGAIN || ret == -ENOMEM)  		goto queue_full; -	if (ret < 0) -		return ret; -	return 1; +	/* fabric drivers should only return -EAGAIN or -ENOMEM as error */ +	WARN_ON(ret); + +	return (!ret) ? 0 : TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -out_fail: -	cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; -	cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	return -EINVAL;  queue_full:  	pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd);  	cmd->t_state = TRANSPORT_COMPLETE_QF_WP; @@ -2839,21 +2570,9 @@ static int transport_get_sense_codes(  	return 0;  } -static int transport_set_sense_codes( -	struct se_cmd *cmd, -	u8 asc, -	u8 ascq) -{ -	cmd->scsi_asc = asc; -	cmd->scsi_ascq = ascq; - -	return 0; -} - -int transport_send_check_condition_and_sense( -	struct se_cmd *cmd, -	u8 reason, -	int from_transport) +int +transport_send_check_condition_and_sense(struct se_cmd *cmd, +		sense_reason_t reason, int from_transport)  {  	unsigned char *buffer = cmd->sense_buffer;  	unsigned long flags; @@ -3044,23 +2763,19 @@ EXPORT_SYMBOL(transport_send_check_condition_and_sense);  int transport_check_aborted_status(struct se_cmd *cmd, int send_status)  { -	int ret = 0; +	if (!(cmd->transport_state & CMD_T_ABORTED)) +		return 0; -	if (cmd->transport_state & CMD_T_ABORTED) { -		if (!send_status || -		     (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) -			return 1; +	if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) +		return 1; -		pr_debug("Sending delayed SAM_STAT_TASK_ABORTED" -			" status for CDB: 0x%02x ITT: 0x%08x\n", -			cmd->t_task_cdb[0], -			cmd->se_tfo->get_task_tag(cmd)); +	pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", +		 cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); -		cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; -		cmd->se_tfo->queue_status(cmd); -		ret = 1; -	} -	return ret; +	cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; +	cmd->se_tfo->queue_status(cmd); + +	return 1;  }  EXPORT_SYMBOL(transport_check_aborted_status); diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 6666a0c74f60..bf0e390ce2d7 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -3,8 +3,7 @@   *   * This file contains logic for SPC-3 Unit Attention emulation   * - * Copyright (c) 2009,2010 Rising Tide Systems - * Copyright (c) 2009,2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC.   *   * Nicholas A. Bellinger <[email protected]>   * @@ -38,9 +37,8 @@  #include "target_core_pr.h"  #include "target_core_ua.h" -int core_scsi3_ua_check( -	struct se_cmd *cmd, -	unsigned char *cdb) +sense_reason_t +target_scsi3_ua_check(struct se_cmd *cmd)  {  	struct se_dev_entry *deve;  	struct se_session *sess = cmd->se_sess; @@ -71,16 +69,14 @@ int core_scsi3_ua_check(  	 *    was received, then the device server shall process the command  	 *    and either:  	 */ -	switch (cdb[0]) { +	switch (cmd->t_task_cdb[0]) {  	case INQUIRY:  	case REPORT_LUNS:  	case REQUEST_SENSE:  		return 0;  	default: -		return -EINVAL; +		return TCM_CHECK_CONDITION_UNIT_ATTENTION;  	} - -	return -EINVAL;  }  int core_scsi3_ua_allocate( @@ -237,7 +233,7 @@ void core_scsi3_ua_for_check_condition(  		 * highest priority UNIT_ATTENTION and ASC/ASCQ without  		 * clearing it.  		 */ -		if (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl != 0) { +		if (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) {  			*asc = ua->ua_asc;  			*ascq = ua->ua_ascq;  			break; @@ -265,8 +261,8 @@ void core_scsi3_ua_for_check_condition(  		" INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x"  		" reported ASC: 0x%02x, ASCQ: 0x%02x\n",  		nacl->se_tpg->se_tpg_tfo->get_fabric_name(), -		(dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : -		"Releasing", dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl, +		(dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : +		"Releasing", dev->dev_attrib.emulate_ua_intlck_ctrl,  		cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq);  } diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index 6e6b03460a1a..0204952fe4d3 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -26,7 +26,7 @@  extern struct kmem_cache *se_ua_cache; -extern int core_scsi3_ua_check(struct se_cmd *, unsigned char *); +extern sense_reason_t target_scsi3_ua_check(struct se_cmd *);  extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8);  extern void core_scsi3_ua_release_all(struct se_dev_entry *);  extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 9585010964ec..12d6fa21e5e1 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -430,7 +430,6 @@ static void ft_sess_rcu_free(struct rcu_head *rcu)  {  	struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); -	transport_deregister_session(sess->se_sess);  	kfree(sess);  } @@ -438,6 +437,7 @@ static void ft_sess_free(struct kref *kref)  {  	struct ft_sess *sess = container_of(kref, struct ft_sess, kref); +	transport_deregister_session(sess->se_sess);  	call_rcu(&sess->rcu, ft_sess_rcu_free);  } |