diff options
| author | Hannes Reinecke <hare@suse.de> | 2014-11-26 08:58:57 -0500 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-12-02 00:36:21 -0500 |
| commit | 506787a2c7daed45f0a213674ca706cbc83a9089 (patch) | |
| tree | d8734240e8977854cc1845d7fa173d76bc3d923c /drivers/target/loopback | |
| parent | 4b2f57e5ced40e91cbf8886d7dc40a9474d2f5c0 (diff) | |
tcm_loop: Fix wrong I_T nexus association
tcm_loop has the I_T nexus associated with the HBA. This causes
commands to become misdirected if the HBA has more than one
target portal group; any command is then being sent to the
first target portal group instead of the correct one.
The nexus needs to be associated with the target portal group
instead.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Cc: <stable@vger.kernel.org> # 3.0+
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/loopback')
| -rw-r--r-- | drivers/target/loopback/tcm_loop.c | 66 | ||||
| -rw-r--r-- | drivers/target/loopback/tcm_loop.h | 7 |
2 files changed, 24 insertions, 49 deletions
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index ab3ab27d49b7..0be83e788df2 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c | |||
| @@ -190,7 +190,7 @@ static void tcm_loop_submission_work(struct work_struct *work) | |||
| 190 | set_host_byte(sc, DID_TRANSPORT_DISRUPTED); | 190 | set_host_byte(sc, DID_TRANSPORT_DISRUPTED); |
| 191 | goto out_done; | 191 | goto out_done; |
| 192 | } | 192 | } |
| 193 | tl_nexus = tl_hba->tl_nexus; | 193 | tl_nexus = tl_tpg->tl_nexus; |
| 194 | if (!tl_nexus) { | 194 | if (!tl_nexus) { |
| 195 | scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" | 195 | scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" |
| 196 | " does not exist\n"); | 196 | " does not exist\n"); |
| @@ -270,16 +270,26 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) | |||
| 270 | * to struct scsi_device | 270 | * to struct scsi_device |
| 271 | */ | 271 | */ |
| 272 | static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, | 272 | static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, |
| 273 | struct tcm_loop_nexus *tl_nexus, | ||
| 274 | int lun, int task, enum tcm_tmreq_table tmr) | 273 | int lun, int task, enum tcm_tmreq_table tmr) |
| 275 | { | 274 | { |
| 276 | struct se_cmd *se_cmd = NULL; | 275 | struct se_cmd *se_cmd = NULL; |
| 277 | struct se_session *se_sess; | 276 | struct se_session *se_sess; |
| 278 | struct se_portal_group *se_tpg; | 277 | struct se_portal_group *se_tpg; |
| 278 | struct tcm_loop_nexus *tl_nexus; | ||
| 279 | struct tcm_loop_cmd *tl_cmd = NULL; | 279 | struct tcm_loop_cmd *tl_cmd = NULL; |
| 280 | struct tcm_loop_tmr *tl_tmr = NULL; | 280 | struct tcm_loop_tmr *tl_tmr = NULL; |
| 281 | int ret = TMR_FUNCTION_FAILED, rc; | 281 | int ret = TMR_FUNCTION_FAILED, rc; |
| 282 | 282 | ||
| 283 | /* | ||
| 284 | * Locate the tl_nexus and se_sess pointers | ||
| 285 | */ | ||
| 286 | tl_nexus = tl_tpg->tl_nexus; | ||
| 287 | if (!tl_nexus) { | ||
| 288 | pr_err("Unable to perform device reset without" | ||
| 289 | " active I_T Nexus\n"); | ||
| 290 | return ret; | ||
| 291 | } | ||
| 292 | |||
| 283 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); | 293 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); |
| 284 | if (!tl_cmd) { | 294 | if (!tl_cmd) { |
| 285 | pr_err("Unable to allocate memory for tl_cmd\n"); | 295 | pr_err("Unable to allocate memory for tl_cmd\n"); |
| @@ -295,7 +305,7 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, | |||
| 295 | 305 | ||
| 296 | se_cmd = &tl_cmd->tl_se_cmd; | 306 | se_cmd = &tl_cmd->tl_se_cmd; |
| 297 | se_tpg = &tl_tpg->tl_se_tpg; | 307 | se_tpg = &tl_tpg->tl_se_tpg; |
| 298 | se_sess = tl_nexus->se_sess; | 308 | se_sess = tl_tpg->tl_nexus->se_sess; |
| 299 | /* | 309 | /* |
| 300 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure | 310 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure |
| 301 | */ | 311 | */ |
| @@ -340,7 +350,6 @@ release: | |||
| 340 | static int tcm_loop_abort_task(struct scsi_cmnd *sc) | 350 | static int tcm_loop_abort_task(struct scsi_cmnd *sc) |
| 341 | { | 351 | { |
| 342 | struct tcm_loop_hba *tl_hba; | 352 | struct tcm_loop_hba *tl_hba; |
| 343 | struct tcm_loop_nexus *tl_nexus; | ||
| 344 | struct tcm_loop_tpg *tl_tpg; | 353 | struct tcm_loop_tpg *tl_tpg; |
| 345 | int ret = FAILED; | 354 | int ret = FAILED; |
| 346 | 355 | ||
| @@ -348,21 +357,8 @@ static int tcm_loop_abort_task(struct scsi_cmnd *sc) | |||
| 348 | * Locate the tcm_loop_hba_t pointer | 357 | * Locate the tcm_loop_hba_t pointer |
| 349 | */ | 358 | */ |
| 350 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | 359 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); |
| 351 | /* | ||
| 352 | * Locate the tl_nexus and se_sess pointers | ||
| 353 | */ | ||
| 354 | tl_nexus = tl_hba->tl_nexus; | ||
| 355 | if (!tl_nexus) { | ||
| 356 | pr_err("Unable to perform device reset without" | ||
| 357 | " active I_T Nexus\n"); | ||
| 358 | return FAILED; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 362 | * Locate the tl_tpg pointer from TargetID in sc->device->id | ||
| 363 | */ | ||
| 364 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | 360 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; |
| 365 | ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun, | 361 | ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, |
| 366 | sc->request->tag, TMR_ABORT_TASK); | 362 | sc->request->tag, TMR_ABORT_TASK); |
| 367 | return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; | 363 | return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; |
| 368 | } | 364 | } |
| @@ -374,7 +370,6 @@ static int tcm_loop_abort_task(struct scsi_cmnd *sc) | |||
| 374 | static int tcm_loop_device_reset(struct scsi_cmnd *sc) | 370 | static int tcm_loop_device_reset(struct scsi_cmnd *sc) |
| 375 | { | 371 | { |
| 376 | struct tcm_loop_hba *tl_hba; | 372 | struct tcm_loop_hba *tl_hba; |
| 377 | struct tcm_loop_nexus *tl_nexus; | ||
| 378 | struct tcm_loop_tpg *tl_tpg; | 373 | struct tcm_loop_tpg *tl_tpg; |
| 379 | int ret = FAILED; | 374 | int ret = FAILED; |
| 380 | 375 | ||
| @@ -382,20 +377,9 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) | |||
| 382 | * Locate the tcm_loop_hba_t pointer | 377 | * Locate the tcm_loop_hba_t pointer |
| 383 | */ | 378 | */ |
| 384 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | 379 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); |
| 385 | /* | ||
| 386 | * Locate the tl_nexus and se_sess pointers | ||
| 387 | */ | ||
| 388 | tl_nexus = tl_hba->tl_nexus; | ||
| 389 | if (!tl_nexus) { | ||
| 390 | pr_err("Unable to perform device reset without" | ||
| 391 | " active I_T Nexus\n"); | ||
| 392 | return FAILED; | ||
| 393 | } | ||
| 394 | /* | ||
| 395 | * Locate the tl_tpg pointer from TargetID in sc->device->id | ||
| 396 | */ | ||
| 397 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | 380 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; |
| 398 | ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun, | 381 | |
| 382 | ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, | ||
| 399 | 0, TMR_LUN_RESET); | 383 | 0, TMR_LUN_RESET); |
| 400 | return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; | 384 | return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; |
| 401 | } | 385 | } |
| @@ -1005,8 +989,8 @@ static int tcm_loop_make_nexus( | |||
| 1005 | struct tcm_loop_nexus *tl_nexus; | 989 | struct tcm_loop_nexus *tl_nexus; |
| 1006 | int ret = -ENOMEM; | 990 | int ret = -ENOMEM; |
| 1007 | 991 | ||
| 1008 | if (tl_tpg->tl_hba->tl_nexus) { | 992 | if (tl_tpg->tl_nexus) { |
| 1009 | pr_debug("tl_tpg->tl_hba->tl_nexus already exists\n"); | 993 | pr_debug("tl_tpg->tl_nexus already exists\n"); |
| 1010 | return -EEXIST; | 994 | return -EEXIST; |
| 1011 | } | 995 | } |
| 1012 | se_tpg = &tl_tpg->tl_se_tpg; | 996 | se_tpg = &tl_tpg->tl_se_tpg; |
| @@ -1041,7 +1025,7 @@ static int tcm_loop_make_nexus( | |||
| 1041 | */ | 1025 | */ |
| 1042 | __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, | 1026 | __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, |
| 1043 | tl_nexus->se_sess, tl_nexus); | 1027 | tl_nexus->se_sess, tl_nexus); |
| 1044 | tl_tpg->tl_hba->tl_nexus = tl_nexus; | 1028 | tl_tpg->tl_nexus = tl_nexus; |
| 1045 | pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" | 1029 | pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" |
| 1046 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), | 1030 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), |
| 1047 | name); | 1031 | name); |
| @@ -1057,12 +1041,8 @@ static int tcm_loop_drop_nexus( | |||
| 1057 | { | 1041 | { |
| 1058 | struct se_session *se_sess; | 1042 | struct se_session *se_sess; |
| 1059 | struct tcm_loop_nexus *tl_nexus; | 1043 | struct tcm_loop_nexus *tl_nexus; |
| 1060 | struct tcm_loop_hba *tl_hba = tpg->tl_hba; | ||
| 1061 | 1044 | ||
| 1062 | if (!tl_hba) | 1045 | tl_nexus = tpg->tl_nexus; |
| 1063 | return -ENODEV; | ||
| 1064 | |||
| 1065 | tl_nexus = tl_hba->tl_nexus; | ||
| 1066 | if (!tl_nexus) | 1046 | if (!tl_nexus) |
| 1067 | return -ENODEV; | 1047 | return -ENODEV; |
| 1068 | 1048 | ||
| @@ -1078,13 +1058,13 @@ static int tcm_loop_drop_nexus( | |||
| 1078 | } | 1058 | } |
| 1079 | 1059 | ||
| 1080 | pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" | 1060 | pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" |
| 1081 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), | 1061 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tpg->tl_hba), |
| 1082 | tl_nexus->se_sess->se_node_acl->initiatorname); | 1062 | tl_nexus->se_sess->se_node_acl->initiatorname); |
| 1083 | /* | 1063 | /* |
| 1084 | * Release the SCSI I_T Nexus to the emulated SAS Target Port | 1064 | * Release the SCSI I_T Nexus to the emulated SAS Target Port |
| 1085 | */ | 1065 | */ |
| 1086 | transport_deregister_session(tl_nexus->se_sess); | 1066 | transport_deregister_session(tl_nexus->se_sess); |
| 1087 | tpg->tl_hba->tl_nexus = NULL; | 1067 | tpg->tl_nexus = NULL; |
| 1088 | kfree(tl_nexus); | 1068 | kfree(tl_nexus); |
| 1089 | return 0; | 1069 | return 0; |
| 1090 | } | 1070 | } |
| @@ -1100,7 +1080,7 @@ static ssize_t tcm_loop_tpg_show_nexus( | |||
| 1100 | struct tcm_loop_nexus *tl_nexus; | 1080 | struct tcm_loop_nexus *tl_nexus; |
| 1101 | ssize_t ret; | 1081 | ssize_t ret; |
| 1102 | 1082 | ||
| 1103 | tl_nexus = tl_tpg->tl_hba->tl_nexus; | 1083 | tl_nexus = tl_tpg->tl_nexus; |
| 1104 | if (!tl_nexus) | 1084 | if (!tl_nexus) |
| 1105 | return -ENODEV; | 1085 | return -ENODEV; |
| 1106 | 1086 | ||
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 54c59d0b6608..6ae49f272ba6 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h | |||
| @@ -27,11 +27,6 @@ struct tcm_loop_tmr { | |||
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | struct tcm_loop_nexus { | 29 | struct tcm_loop_nexus { |
| 30 | int it_nexus_active; | ||
| 31 | /* | ||
| 32 | * Pointer to Linux/SCSI HBA from linux/include/scsi_host.h | ||
| 33 | */ | ||
| 34 | struct scsi_host *sh; | ||
| 35 | /* | 30 | /* |
| 36 | * Pointer to TCM session for I_T Nexus | 31 | * Pointer to TCM session for I_T Nexus |
| 37 | */ | 32 | */ |
| @@ -51,6 +46,7 @@ struct tcm_loop_tpg { | |||
| 51 | atomic_t tl_tpg_port_count; | 46 | atomic_t tl_tpg_port_count; |
| 52 | struct se_portal_group tl_se_tpg; | 47 | struct se_portal_group tl_se_tpg; |
| 53 | struct tcm_loop_hba *tl_hba; | 48 | struct tcm_loop_hba *tl_hba; |
| 49 | struct tcm_loop_nexus *tl_nexus; | ||
| 54 | }; | 50 | }; |
| 55 | 51 | ||
| 56 | struct tcm_loop_hba { | 52 | struct tcm_loop_hba { |
| @@ -59,7 +55,6 @@ struct tcm_loop_hba { | |||
| 59 | struct se_hba_s *se_hba; | 55 | struct se_hba_s *se_hba; |
| 60 | struct se_lun *tl_hba_lun; | 56 | struct se_lun *tl_hba_lun; |
| 61 | struct se_port *tl_hba_lun_sep; | 57 | struct se_port *tl_hba_lun_sep; |
| 62 | struct tcm_loop_nexus *tl_nexus; | ||
| 63 | struct device dev; | 58 | struct device dev; |
| 64 | struct Scsi_Host *sh; | 59 | struct Scsi_Host *sh; |
| 65 | struct tcm_loop_tpg tl_hba_tpgs[TL_TPGS_PER_HBA]; | 60 | struct tcm_loop_tpg tl_hba_tpgs[TL_TPGS_PER_HBA]; |
