diff options
| author | Hannes Reinecke <hare@suse.de> | 2013-10-16 03:12:55 -0400 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-10-16 18:41:50 -0400 |
| commit | 969871cdc2d0f5a81d6733450b5334d14fce2b75 (patch) | |
| tree | 3f6f35aaa3cc3f10f3e31f68a47a72bfa1b17f3d /drivers/target/loopback | |
| parent | a314d7003ccd4f4886d1280ff4f6c00217fc9ae3 (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>
Diffstat (limited to 'drivers/target/loopback')
| -rw-r--r-- | drivers/target/loopback/tcm_loop.c | 71 | ||||
| -rw-r--r-- | drivers/target/loopback/tcm_loop.h | 2 |
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 | ||
| 138 | static 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 | */ |
| 248 | static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, | 264 | static 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 | ||
| 332 | static 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 | ||
| 352 | static int tcm_loop_slave_configure(struct scsi_device *sd) | 401 | static 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 | ||
| 720 | static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) | 780 | static 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 | ||
| 725 | static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) | 788 | static 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 @@ | |||
| 10 | struct tcm_loop_cmd { | 10 | struct 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() */ |
