aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2013-10-16 03:12:55 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-10-16 18:41:50 -0400
commit969871cdc2d0f5a81d6733450b5334d14fce2b75 (patch)
tree3f6f35aaa3cc3f10f3e31f68a47a72bfa1b17f3d
parenta314d7003ccd4f4886d1280ff4f6c00217fc9ae3 (diff)
tcm_loop: TCQ and command abort support
Implement TCQ support, which enables us to do proper command abort, too. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/loopback/tcm_loop.c71
-rw-r--r--drivers/target/loopback/tcm_loop.h2
2 files changed, 69 insertions, 4 deletions
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 783675f7cdab..04811caac487 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -135,6 +135,21 @@ static int tcm_loop_change_queue_depth(
135 return sdev->queue_depth; 135 return sdev->queue_depth;
136} 136}
137 137
138static int tcm_loop_change_queue_type(struct scsi_device *sdev, int tag)
139{
140 if (sdev->tagged_supported) {
141 scsi_set_tag_type(sdev, tag);
142
143 if (tag)
144 scsi_activate_tcq(sdev, sdev->queue_depth);
145 else
146 scsi_deactivate_tcq(sdev, sdev->queue_depth);
147 } else
148 tag = 0;
149
150 return tag;
151}
152
138/* 153/*
139 * Locate the SAM Task Attr from struct scsi_cmnd * 154 * Locate the SAM Task Attr from struct scsi_cmnd *
140 */ 155 */
@@ -236,6 +251,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
236 } 251 }
237 252
238 tl_cmd->sc = sc; 253 tl_cmd->sc = sc;
254 tl_cmd->sc_cmd_tag = sc->tag;
239 INIT_WORK(&tl_cmd->work, tcm_loop_submission_work); 255 INIT_WORK(&tl_cmd->work, tcm_loop_submission_work);
240 queue_work(tcm_loop_workqueue, &tl_cmd->work); 256 queue_work(tcm_loop_workqueue, &tl_cmd->work);
241 return 0; 257 return 0;
@@ -247,7 +263,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
247 */ 263 */
248static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, 264static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
249 struct tcm_loop_nexus *tl_nexus, 265 struct tcm_loop_nexus *tl_nexus,
250 int lun, enum tcm_tmreq_table tmr) 266 int lun, int task, enum tcm_tmreq_table tmr)
251{ 267{
252 struct se_cmd *se_cmd = NULL; 268 struct se_cmd *se_cmd = NULL;
253 struct se_session *se_sess; 269 struct se_session *se_sess;
@@ -283,6 +299,9 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
283 if (rc < 0) 299 if (rc < 0)
284 goto release; 300 goto release;
285 301
302 if (tmr == TMR_ABORT_TASK)
303 se_cmd->se_tmr_req->ref_task_tag = task;
304
286 /* 305 /*
287 * Locate the underlying TCM struct se_lun 306 * Locate the underlying TCM struct se_lun
288 */ 307 */
@@ -310,6 +329,36 @@ release:
310 return ret; 329 return ret;
311} 330}
312 331
332static int tcm_loop_abort_task(struct scsi_cmnd *sc)
333{
334 struct tcm_loop_hba *tl_hba;
335 struct tcm_loop_nexus *tl_nexus;
336 struct tcm_loop_tpg *tl_tpg;
337 int ret = FAILED;
338
339 /*
340 * Locate the tcm_loop_hba_t pointer
341 */
342 tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
343 /*
344 * Locate the tl_nexus and se_sess pointers
345 */
346 tl_nexus = tl_hba->tl_nexus;
347 if (!tl_nexus) {
348 pr_err("Unable to perform device reset without"
349 " active I_T Nexus\n");
350 return FAILED;
351 }
352
353 /*
354 * Locate the tl_tpg pointer from TargetID in sc->device->id
355 */
356 tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
357 ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun,
358 sc->tag, TMR_ABORT_TASK);
359 return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
360}
361
313/* 362/*
314 * Called from SCSI EH process context to issue a LUN_RESET TMR 363 * Called from SCSI EH process context to issue a LUN_RESET TMR
315 * to struct scsi_device 364 * to struct scsi_device
@@ -338,8 +387,8 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
338 * Locate the tl_tpg pointer from TargetID in sc->device->id 387 * Locate the tl_tpg pointer from TargetID in sc->device->id
339 */ 388 */
340 tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; 389 tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
341 ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, 390 ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun,
342 sc->device->lun, TMR_LUN_RESET); 391 0, TMR_LUN_RESET);
343 return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; 392 return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
344} 393}
345 394
@@ -351,6 +400,15 @@ static int tcm_loop_slave_alloc(struct scsi_device *sd)
351 400
352static int tcm_loop_slave_configure(struct scsi_device *sd) 401static int tcm_loop_slave_configure(struct scsi_device *sd)
353{ 402{
403 if (sd->tagged_supported) {
404 scsi_activate_tcq(sd, sd->queue_depth);
405 scsi_adjust_queue_depth(sd, MSG_SIMPLE_TAG,
406 sd->host->cmd_per_lun);
407 } else {
408 scsi_adjust_queue_depth(sd, 0,
409 sd->host->cmd_per_lun);
410 }
411
354 return 0; 412 return 0;
355} 413}
356 414
@@ -360,6 +418,8 @@ static struct scsi_host_template tcm_loop_driver_template = {
360 .name = "TCM_Loopback", 418 .name = "TCM_Loopback",
361 .queuecommand = tcm_loop_queuecommand, 419 .queuecommand = tcm_loop_queuecommand,
362 .change_queue_depth = tcm_loop_change_queue_depth, 420 .change_queue_depth = tcm_loop_change_queue_depth,
421 .change_queue_type = tcm_loop_change_queue_type,
422 .eh_abort_handler = tcm_loop_abort_task,
363 .eh_device_reset_handler = tcm_loop_device_reset, 423 .eh_device_reset_handler = tcm_loop_device_reset,
364 .can_queue = 1024, 424 .can_queue = 1024,
365 .this_id = -1, 425 .this_id = -1,
@@ -719,7 +779,10 @@ static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl)
719 779
720static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) 780static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd)
721{ 781{
722 return 1; 782 struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
783 struct tcm_loop_cmd, tl_se_cmd);
784
785 return tl_cmd->sc_cmd_tag;
723} 786}
724 787
725static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) 788static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd)
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h
index 56528f7dafae..54c59d0b6608 100644
--- a/drivers/target/loopback/tcm_loop.h
+++ b/drivers/target/loopback/tcm_loop.h
@@ -10,6 +10,8 @@
10struct tcm_loop_cmd { 10struct tcm_loop_cmd {
11 /* State of Linux/SCSI CDB+Data descriptor */ 11 /* State of Linux/SCSI CDB+Data descriptor */
12 u32 sc_cmd_state; 12 u32 sc_cmd_state;
13 /* Tagged command queueing */
14 u32 sc_cmd_tag;
13 /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */ 15 /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */
14 struct scsi_cmnd *sc; 16 struct scsi_cmnd *sc;
15 /* The TCM I/O descriptor that is accessed via container_of() */ 17 /* The TCM I/O descriptor that is accessed via container_of() */