Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a55da8a0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI target fixes from Nicholas Bellinger:
 "Here are the outstanding target-pending fixes for v4.9-rc2.

  This includes:

   - Fix v4.1.y+ reference leak regression with concurrent TMR
     ABORT_TASK + session shutdown. (Vaibhav Tandon)

   - Enable tcm_fc w/ SCF_USE_CPUID to avoid host exchange timeouts
     (Hannes)

   - target/user error sense handling fixes. (Andy + MNC + HCH)

   - Fix iscsi-target NOP_OUT error path iscsi_cmd descriptor leak
     (Varun)

   - Two EXTENDED_COPY SCSI status fixes for ESX VAAI (Dinesh Israni +
     Nixon Vincent)

   - Revert a v4.8 residual overflow change, that breaks sg_inq with
     small allocation lengths.

  There are a number of folks stress testing the v4.1.y regression fix
  in their environments, and more folks doing iser-target I/O stress
  testing atop recent v4.x.y code.

  There is also one v4.2.y+ RCU conversion regression related to
  explicit NodeACL configfs changes, that is still being tracked down"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  target/tcm_fc: use CPU affinity for responses
  target/tcm_fc: Update debugging statements to match libfc usage
  target/tcm_fc: return detailed error in ft_sess_create()
  target/tcm_fc: print command pointer in debug message
  target: fix potential race window in target_sess_cmd_list_waiting()
  Revert "target: Fix residual overflow handling in target_complete_cmd_with_length"
  target: Don't override EXTENDED_COPY xcopy_pt_cmd SCSI status code
  target: Make EXTENDED_COPY 0xe4 failure return COPY TARGET DEVICE NOT REACHABLE
  target: Re-add missing SCF_ACK_KREF assignment in v4.1.y
  iscsi-target: fix iscsi cmd leak
  iscsi-target: fix spelling mistake "Unsolicitied" -> "Unsolicited"
  target/user: Fix comments to not refer to data ring
  target/user: Return an error if cmd data size is too large
  target/user: Use sense_reason_t in tcmu_queue_cmd_ring
parents e6995f22 1ba0158f
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1804,6 +1804,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	 * Otherwise, initiator is not expecting a NOPIN is response.
	 * Just ignore for now.
	 */

	if (cmd)
		iscsit_free_cmd(cmd, false);

        return 0;
}
EXPORT_SYMBOL(iscsit_process_nop_out);
@@ -2982,7 +2986,7 @@ iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,

	pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x,"
		" StatSN: 0x%08x, Length %u\n", (nopout_response) ?
		"Solicitied" : "Unsolicitied", cmd->init_task_tag,
		"Solicited" : "Unsolicited", cmd->init_task_tag,
		cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
}
EXPORT_SYMBOL(iscsit_build_nopin_rsp);
+2 −2
Original line number Diff line number Diff line
@@ -434,7 +434,7 @@ static int iscsi_login_zero_tsih_s2(

		/*
		 * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
		 * Immediate Data + Unsolicitied Data-OUT if necessary..
		 * Immediate Data + Unsolicited Data-OUT if necessary..
		 */
		param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
						  conn->param_list);
@@ -646,7 +646,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
{
	struct iscsi_session *sess = conn->sess;
	/*
	 * FIXME: Unsolicitied NopIN support for ISER
	 * FIXME: Unsolicited NopIN support for ISER
	 */
	if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
		return;
+19 −20
Original line number Diff line number Diff line
@@ -754,15 +754,7 @@ EXPORT_SYMBOL(target_complete_cmd);

void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
{
	if (scsi_status != SAM_STAT_GOOD) {
		return;
	}

	/*
	 * Calculate new residual count based upon length of SCSI data
	 * transferred.
	 */
	if (length < cmd->data_length) {
	if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
		if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
			cmd->residual_count += cmd->data_length - length;
		} else {
@@ -771,12 +763,6 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len
		}

		cmd->data_length = length;
	} else if (length > cmd->data_length) {
		cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
		cmd->residual_count = length - cmd->data_length;
	} else {
		cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT);
		cmd->residual_count = 0;
	}

	target_complete_cmd(cmd, scsi_status);
@@ -1706,6 +1692,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
	case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
	case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
	case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
	case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
		break;
	case TCM_OUT_OF_RESOURCES:
		sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -2547,8 +2534,12 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
	 * fabric acknowledgement that requires two target_put_sess_cmd()
	 * invocations before se_cmd descriptor release.
	 */
	if (ack_kref)
		kref_get(&se_cmd->cmd_kref);
	if (ack_kref) {
		if (!kref_get_unless_zero(&se_cmd->cmd_kref))
			return -EINVAL;

		se_cmd->se_cmd_flags |= SCF_ACK_KREF;
	}

	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
	if (se_sess->sess_tearing_down) {
@@ -2627,7 +2618,7 @@ EXPORT_SYMBOL(target_put_sess_cmd);
 */
void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
{
	struct se_cmd *se_cmd;
	struct se_cmd *se_cmd, *tmp_cmd;
	unsigned long flags;
	int rc;

@@ -2639,14 +2630,16 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
	se_sess->sess_tearing_down = 1;
	list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);

	list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
	list_for_each_entry_safe(se_cmd, tmp_cmd,
				 &se_sess->sess_wait_list, se_cmd_list) {
		rc = kref_get_unless_zero(&se_cmd->cmd_kref);
		if (rc) {
			se_cmd->cmd_wait_set = 1;
			spin_lock(&se_cmd->t_state_lock);
			se_cmd->transport_state |= CMD_T_FABRIC_STOP;
			spin_unlock(&se_cmd->t_state_lock);
		}
		} else
			list_del_init(&se_cmd->se_cmd_list);
	}

	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
@@ -2871,6 +2864,12 @@ static const struct sense_info sense_info_table[] = {
		.ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
		.add_sector_info = true,
	},
	[TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = {
		.key = COPY_ABORTED,
		.asc = 0x0d,
		.ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */

	},
	[TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = {
		/*
		 * Returning ILLEGAL REQUEST would cause immediate IO errors on
+21 −29
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ struct tcmu_dev {
	size_t dev_size;
	u32 cmdr_size;
	u32 cmdr_last_cleaned;
	/* Offset of data ring from start of mb */
	/* Offset of data area from start of mb */
	/* Must add data_off and mb_addr to get the address */
	size_t data_off;
	size_t data_size;
@@ -349,7 +349,7 @@ static inline size_t spc_bitmap_free(unsigned long *bitmap)

/*
 * We can't queue a command until we have space available on the cmd ring *and*
 * space available on the data ring.
 * space available on the data area.
 *
 * Called with ring lock held.
 */
@@ -389,7 +389,8 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d
	return true;
}

static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
static sense_reason_t
tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
{
	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;
	struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
@@ -405,7 +406,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
	DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS);

	if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags))
		return -EINVAL;
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;

	/*
	 * Must be a certain minimum size for response sense info, but
@@ -432,11 +433,14 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
		BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents));
		data_length += se_cmd->t_bidi_data_sg->length;
	}
	if ((command_size > (udev->cmdr_size / 2))
	    || data_length > udev->data_size)
		pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu "
			"cmd/data ring buffers\n", command_size, data_length,
	if ((command_size > (udev->cmdr_size / 2)) ||
	    data_length > udev->data_size) {
		pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu "
			"cmd ring/data area\n", command_size, data_length,
			udev->cmdr_size, udev->data_size);
		spin_unlock_irq(&udev->cmdr_lock);
		return TCM_INVALID_CDB_FIELD;
	}

	while (!is_ring_space_avail(udev, command_size, data_length)) {
		int ret;
@@ -450,7 +454,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
		finish_wait(&udev->wait_cmdr, &__wait);
		if (!ret) {
			pr_warn("tcmu: command timed out\n");
			return -ETIMEDOUT;
			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
		}

		spin_lock_irq(&udev->cmdr_lock);
@@ -487,9 +491,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)

	bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS);

	/*
	 * Fix up iovecs, and handle if allocation in data ring wrapped.
	 */
	/* Handle allocating space from the data area */
	iov = &entry->req.iov[0];
	iov_cnt = 0;
	copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE
@@ -526,10 +528,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
	mod_timer(&udev->timeout,
		round_jiffies_up(jiffies + msecs_to_jiffies(TCMU_TIME_OUT)));

	return 0;
	return TCM_NO_SENSE;
}

static int tcmu_queue_cmd(struct se_cmd *se_cmd)
static sense_reason_t
tcmu_queue_cmd(struct se_cmd *se_cmd)
{
	struct se_device *se_dev = se_cmd->se_dev;
	struct tcmu_dev *udev = TCMU_DEV(se_dev);
@@ -538,10 +541,10 @@ static int tcmu_queue_cmd(struct se_cmd *se_cmd)

	tcmu_cmd = tcmu_alloc_cmd(se_cmd);
	if (!tcmu_cmd)
		return -ENOMEM;
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;

	ret = tcmu_queue_cmd_ring(tcmu_cmd);
	if (ret < 0) {
	if (ret != TCM_NO_SENSE) {
		pr_err("TCMU: Could not queue command\n");
		spin_lock_irq(&udev->commands_lock);
		idr_remove(&udev->commands, tcmu_cmd->cmd_id);
@@ -561,7 +564,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
	if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
		/*
		 * cmd has been completed already from timeout, just reclaim
		 * data ring space and free cmd
		 * data area space and free cmd
		 */
		free_data_area(udev, cmd);

@@ -1128,21 +1131,10 @@ static sector_t tcmu_get_blocks(struct se_device *dev)
		       dev->dev_attrib.block_size);
}

static sense_reason_t
tcmu_pass_op(struct se_cmd *se_cmd)
{
	int ret = tcmu_queue_cmd(se_cmd);

	if (ret != 0)
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
	else
		return TCM_NO_SENSE;
}

static sense_reason_t
tcmu_parse_cdb(struct se_cmd *cmd)
{
	return passthrough_parse_cdb(cmd, tcmu_pass_op);
	return passthrough_parse_cdb(cmd, tcmu_queue_cmd);
}

static const struct target_backend_ops tcmu_ops = {
+26 −8
Original line number Diff line number Diff line
@@ -104,7 +104,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
	}
	mutex_unlock(&g_device_mutex);

	pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
	pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
	return -EINVAL;
}

@@ -185,7 +185,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op

static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
				struct xcopy_op *xop, unsigned char *p,
				unsigned short tdll)
				unsigned short tdll, sense_reason_t *sense_ret)
{
	struct se_device *local_dev = se_cmd->se_dev;
	unsigned char *desc = p;
@@ -193,6 +193,8 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
	unsigned short start = 0;
	bool src = true;

	*sense_ret = TCM_INVALID_PARAMETER_LIST;

	if (offset != 0) {
		pr_err("XCOPY target descriptor list length is not"
			" multiple of %d\n", XCOPY_TARGET_DESC_LEN);
@@ -243,9 +245,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
		rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
	else
		rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);

	if (rc < 0)
	/*
	 * If a matching IEEE NAA 0x83 descriptor for the requested device
	 * is not located on this node, return COPY_ABORTED with ASQ/ASQC
	 * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the
	 * initiator to fall back to normal copy method.
	 */
	if (rc < 0) {
		*sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
		goto out;
	}

	pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
		 xop->src_dev, &xop->src_tid_wwn[0]);
@@ -653,6 +662,7 @@ static int target_xcopy_read_source(
	rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
				remote_port, true);
	if (rc < 0) {
		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
		transport_generic_free_cmd(se_cmd, 0);
		return rc;
	}
@@ -664,6 +674,7 @@ static int target_xcopy_read_source(

	rc = target_xcopy_issue_pt_cmd(xpt_cmd);
	if (rc < 0) {
		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
		transport_generic_free_cmd(se_cmd, 0);
		return rc;
	}
@@ -714,6 +725,7 @@ static int target_xcopy_write_destination(
				remote_port, false);
	if (rc < 0) {
		struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
		/*
		 * If the failure happened before the t_mem_list hand-off in
		 * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
@@ -729,6 +741,7 @@ static int target_xcopy_write_destination(

	rc = target_xcopy_issue_pt_cmd(xpt_cmd);
	if (rc < 0) {
		ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
		se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
		transport_generic_free_cmd(se_cmd, 0);
		return rc;
@@ -815,9 +828,14 @@ static void target_xcopy_do_work(struct work_struct *work)
out:
	xcopy_pt_undepend_remotedev(xop);
	kfree(xop);

	pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n");
	/*
	 * Don't override an error scsi status if it has already been set
	 */
	if (ec_cmd->scsi_status == SAM_STAT_GOOD) {
		pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY"
			" CHECK_CONDITION -> sending response\n", rc);
		ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
	}
	target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION);
}

@@ -875,7 +893,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
		" tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
		tdll, sdll, inline_dl);

	rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll);
	rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
	if (rc <= 0)
		goto out;

Loading