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

Commit 969871cd authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Nicholas Bellinger
Browse files

tcm_loop: TCQ and command abort support



Implement TCQ support, which enables us to do proper command
abort, too.

Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent a314d700
Loading
Loading
Loading
Loading
+67 −4
Original line number Original line Diff line number Diff line
@@ -135,6 +135,21 @@ static int tcm_loop_change_queue_depth(
	return sdev->queue_depth;
	return sdev->queue_depth;
}
}


static int tcm_loop_change_queue_type(struct scsi_device *sdev, int tag)
{
	if (sdev->tagged_supported) {
		scsi_set_tag_type(sdev, tag);

		if (tag)
			scsi_activate_tcq(sdev, sdev->queue_depth);
		else
			scsi_deactivate_tcq(sdev, sdev->queue_depth);
	} else
		tag = 0;

	return tag;
}

/*
/*
 * Locate the SAM Task Attr from struct scsi_cmnd *
 * Locate the SAM Task Attr from struct scsi_cmnd *
 */
 */
@@ -236,6 +251,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
	}
	}


	tl_cmd->sc = sc;
	tl_cmd->sc = sc;
	tl_cmd->sc_cmd_tag = sc->tag;
	INIT_WORK(&tl_cmd->work, tcm_loop_submission_work);
	INIT_WORK(&tl_cmd->work, tcm_loop_submission_work);
	queue_work(tcm_loop_workqueue, &tl_cmd->work);
	queue_work(tcm_loop_workqueue, &tl_cmd->work);
	return 0;
	return 0;
@@ -247,7 +263,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
 */
 */
static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
			      struct tcm_loop_nexus *tl_nexus,
			      struct tcm_loop_nexus *tl_nexus,
			      int lun, enum tcm_tmreq_table tmr)
			      int lun, int task, enum tcm_tmreq_table tmr)
{
{
	struct se_cmd *se_cmd = NULL;
	struct se_cmd *se_cmd = NULL;
	struct se_session *se_sess;
	struct se_session *se_sess;
@@ -283,6 +299,9 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
	if (rc < 0)
	if (rc < 0)
		goto release;
		goto release;


	if (tmr == TMR_ABORT_TASK)
		se_cmd->se_tmr_req->ref_task_tag = task;

	/*
	/*
	 * Locate the underlying TCM struct se_lun
	 * Locate the underlying TCM struct se_lun
	 */
	 */
@@ -310,6 +329,36 @@ release:
	return ret;
	return ret;
}
}


static int tcm_loop_abort_task(struct scsi_cmnd *sc)
{
	struct tcm_loop_hba *tl_hba;
	struct tcm_loop_nexus *tl_nexus;
	struct tcm_loop_tpg *tl_tpg;
	int ret = FAILED;

	/*
	 * Locate the tcm_loop_hba_t pointer
	 */
	tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
	/*
	 * Locate the tl_nexus and se_sess pointers
	 */
	tl_nexus = tl_hba->tl_nexus;
	if (!tl_nexus) {
		pr_err("Unable to perform device reset without"
				" active I_T Nexus\n");
		return FAILED;
	}

	/*
	 * Locate the tl_tpg pointer from TargetID in sc->device->id
	 */
	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
	ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun,
				 sc->tag, TMR_ABORT_TASK);
	return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}

/*
/*
 * Called from SCSI EH process context to issue a LUN_RESET TMR
 * Called from SCSI EH process context to issue a LUN_RESET TMR
 * to struct scsi_device
 * to struct scsi_device
@@ -338,8 +387,8 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
	 * Locate the tl_tpg pointer from TargetID in sc->device->id
	 * Locate the tl_tpg pointer from TargetID in sc->device->id
	 */
	 */
	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
	ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus,
	ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun,
				 sc->device->lun, TMR_LUN_RESET);
				 0, TMR_LUN_RESET);
	return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
	return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}
}


@@ -351,6 +400,15 @@ static int tcm_loop_slave_alloc(struct scsi_device *sd)


static int tcm_loop_slave_configure(struct scsi_device *sd)
static int tcm_loop_slave_configure(struct scsi_device *sd)
{
{
	if (sd->tagged_supported) {
		scsi_activate_tcq(sd, sd->queue_depth);
		scsi_adjust_queue_depth(sd, MSG_SIMPLE_TAG,
					sd->host->cmd_per_lun);
	} else {
		scsi_adjust_queue_depth(sd, 0,
					sd->host->cmd_per_lun);
	}

	return 0;
	return 0;
}
}


@@ -360,6 +418,8 @@ static struct scsi_host_template tcm_loop_driver_template = {
	.name			= "TCM_Loopback",
	.name			= "TCM_Loopback",
	.queuecommand		= tcm_loop_queuecommand,
	.queuecommand		= tcm_loop_queuecommand,
	.change_queue_depth	= tcm_loop_change_queue_depth,
	.change_queue_depth	= tcm_loop_change_queue_depth,
	.change_queue_type	= tcm_loop_change_queue_type,
	.eh_abort_handler = tcm_loop_abort_task,
	.eh_device_reset_handler = tcm_loop_device_reset,
	.eh_device_reset_handler = tcm_loop_device_reset,
	.can_queue		= 1024,
	.can_queue		= 1024,
	.this_id		= -1,
	.this_id		= -1,
@@ -719,7 +779,10 @@ static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl)


static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd)
static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd)
{
{
	return 1;
	struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
			struct tcm_loop_cmd, tl_se_cmd);

	return tl_cmd->sc_cmd_tag;
}
}


static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd)
static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd)
+2 −0
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@
struct tcm_loop_cmd {
struct tcm_loop_cmd {
	/* State of Linux/SCSI CDB+Data descriptor */
	/* State of Linux/SCSI CDB+Data descriptor */
	u32 sc_cmd_state;
	u32 sc_cmd_state;
	/* Tagged command queueing */
	u32 sc_cmd_tag;
	/* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */
	/* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */
	struct scsi_cmnd *sc;
	struct scsi_cmnd *sc;
	/* The TCM I/O descriptor that is accessed via container_of() */
	/* The TCM I/O descriptor that is accessed via container_of() */