diff options
| -rw-r--r-- | drivers/target/tcm_fc/tcm_fc.h | 12 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 90 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_conf.c | 7 |
3 files changed, 16 insertions, 93 deletions
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index bd4fe21a23b8..3749d8b4b423 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h | |||
| @@ -98,8 +98,7 @@ struct ft_tpg { | |||
| 98 | struct list_head list; /* linkage in ft_lport_acl tpg_list */ | 98 | struct list_head list; /* linkage in ft_lport_acl tpg_list */ |
| 99 | struct list_head lun_list; /* head of LUNs */ | 99 | struct list_head lun_list; /* head of LUNs */ |
| 100 | struct se_portal_group se_tpg; | 100 | struct se_portal_group se_tpg; |
| 101 | struct task_struct *thread; /* processing thread */ | 101 | struct workqueue_struct *workqueue; |
| 102 | struct se_queue_obj qobj; /* queue for processing thread */ | ||
| 103 | }; | 102 | }; |
| 104 | 103 | ||
| 105 | struct ft_lport_acl { | 104 | struct ft_lport_acl { |
| @@ -110,16 +109,10 @@ struct ft_lport_acl { | |||
| 110 | struct se_wwn fc_lport_wwn; | 109 | struct se_wwn fc_lport_wwn; |
| 111 | }; | 110 | }; |
| 112 | 111 | ||
| 113 | enum ft_cmd_state { | ||
| 114 | FC_CMD_ST_NEW = 0, | ||
| 115 | FC_CMD_ST_REJ | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* | 112 | /* |
| 119 | * Commands | 113 | * Commands |
| 120 | */ | 114 | */ |
| 121 | struct ft_cmd { | 115 | struct ft_cmd { |
| 122 | enum ft_cmd_state state; | ||
| 123 | u32 lun; /* LUN from request */ | 116 | u32 lun; /* LUN from request */ |
| 124 | struct ft_sess *sess; /* session held for cmd */ | 117 | struct ft_sess *sess; /* session held for cmd */ |
| 125 | struct fc_seq *seq; /* sequence in exchange mgr */ | 118 | struct fc_seq *seq; /* sequence in exchange mgr */ |
| @@ -127,7 +120,7 @@ struct ft_cmd { | |||
| 127 | struct fc_frame *req_frame; | 120 | struct fc_frame *req_frame; |
| 128 | unsigned char *cdb; /* pointer to CDB inside frame */ | 121 | unsigned char *cdb; /* pointer to CDB inside frame */ |
| 129 | u32 write_data_len; /* data received on writes */ | 122 | u32 write_data_len; /* data received on writes */ |
| 130 | struct se_queue_req se_req; | 123 | struct work_struct work; |
| 131 | /* Local sense buffer */ | 124 | /* Local sense buffer */ |
| 132 | unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; | 125 | unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; |
| 133 | u32 was_ddp_setup:1; /* Set only if ddp is setup */ | 126 | u32 was_ddp_setup:1; /* Set only if ddp is setup */ |
| @@ -177,7 +170,6 @@ int ft_is_state_remove(struct se_cmd *); | |||
| 177 | /* | 170 | /* |
| 178 | * other internal functions. | 171 | * other internal functions. |
| 179 | */ | 172 | */ |
| 180 | int ft_thread(void *); | ||
| 181 | void ft_recv_req(struct ft_sess *, struct fc_frame *); | 173 | void ft_recv_req(struct ft_sess *, struct fc_frame *); |
| 182 | struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); | 174 | struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); |
| 183 | struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); | 175 | struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); |
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 5654dc22f7ae..80fbcde00cb6 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
| @@ -62,8 +62,8 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
| 62 | int count; | 62 | int count; |
| 63 | 63 | ||
| 64 | se_cmd = &cmd->se_cmd; | 64 | se_cmd = &cmd->se_cmd; |
| 65 | pr_debug("%s: cmd %p state %d sess %p seq %p se_cmd %p\n", | 65 | pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", |
| 66 | caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); | 66 | caller, cmd, cmd->sess, cmd->seq, se_cmd); |
| 67 | pr_debug("%s: cmd %p cdb %p\n", | 67 | pr_debug("%s: cmd %p cdb %p\n", |
| 68 | caller, cmd, cmd->cdb); | 68 | caller, cmd, cmd->cdb); |
| 69 | pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun); | 69 | pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun); |
| @@ -90,38 +90,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
| 90 | 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); | 90 | 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) | ||
| 94 | { | ||
| 95 | struct ft_tpg *tpg = sess->tport->tpg; | ||
| 96 | struct se_queue_obj *qobj = &tpg->qobj; | ||
| 97 | unsigned long flags; | ||
| 98 | |||
| 99 | qobj = &sess->tport->tpg->qobj; | ||
| 100 | spin_lock_irqsave(&qobj->cmd_queue_lock, flags); | ||
| 101 | list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); | ||
| 102 | atomic_inc(&qobj->queue_cnt); | ||
| 103 | spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); | ||
| 104 | |||
| 105 | wake_up_process(tpg->thread); | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) | ||
| 109 | { | ||
| 110 | unsigned long flags; | ||
| 111 | struct se_queue_req *qr; | ||
| 112 | |||
| 113 | spin_lock_irqsave(&qobj->cmd_queue_lock, flags); | ||
| 114 | if (list_empty(&qobj->qobj_list)) { | ||
| 115 | spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); | ||
| 116 | return NULL; | ||
| 117 | } | ||
| 118 | qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); | ||
| 119 | list_del(&qr->qr_list); | ||
| 120 | atomic_dec(&qobj->queue_cnt); | ||
| 121 | spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); | ||
| 122 | return container_of(qr, struct ft_cmd, se_req); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void ft_free_cmd(struct ft_cmd *cmd) | 93 | static void ft_free_cmd(struct ft_cmd *cmd) |
| 126 | { | 94 | { |
| 127 | struct fc_frame *fp; | 95 | struct fc_frame *fp; |
| @@ -282,9 +250,7 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) | |||
| 282 | 250 | ||
| 283 | int ft_get_cmd_state(struct se_cmd *se_cmd) | 251 | int ft_get_cmd_state(struct se_cmd *se_cmd) |
| 284 | { | 252 | { |
| 285 | struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); | 253 | return 0; |
| 286 | |||
| 287 | return cmd->state; | ||
| 288 | } | 254 | } |
| 289 | 255 | ||
| 290 | int ft_is_state_remove(struct se_cmd *se_cmd) | 256 | int ft_is_state_remove(struct se_cmd *se_cmd) |
| @@ -505,6 +471,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) | |||
| 505 | return 0; | 471 | return 0; |
| 506 | } | 472 | } |
| 507 | 473 | ||
| 474 | static void ft_send_work(struct work_struct *work); | ||
| 475 | |||
| 508 | /* | 476 | /* |
| 509 | * Handle incoming FCP command. | 477 | * Handle incoming FCP command. |
| 510 | */ | 478 | */ |
| @@ -523,7 +491,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) | |||
| 523 | goto busy; | 491 | goto busy; |
| 524 | } | 492 | } |
| 525 | cmd->req_frame = fp; /* hold frame during cmd */ | 493 | cmd->req_frame = fp; /* hold frame during cmd */ |
| 526 | ft_queue_cmd(sess, cmd); | 494 | |
| 495 | INIT_WORK(&cmd->work, ft_send_work); | ||
| 496 | queue_work(sess->tport->tpg->workqueue, &cmd->work); | ||
| 527 | return; | 497 | return; |
| 528 | 498 | ||
| 529 | busy: | 499 | busy: |
| @@ -563,12 +533,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) | |||
| 563 | /* | 533 | /* |
| 564 | * Send new command to target. | 534 | * Send new command to target. |
| 565 | */ | 535 | */ |
| 566 | static void ft_send_cmd(struct ft_cmd *cmd) | 536 | static void ft_send_work(struct work_struct *work) |
| 567 | { | 537 | { |
| 538 | struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); | ||
| 568 | struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); | 539 | struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); |
| 569 | struct se_cmd *se_cmd; | 540 | struct se_cmd *se_cmd; |
| 570 | struct fcp_cmnd *fcp; | 541 | struct fcp_cmnd *fcp; |
| 571 | int data_dir; | 542 | int data_dir = 0; |
| 572 | u32 data_len; | 543 | u32 data_len; |
| 573 | int task_attr; | 544 | int task_attr; |
| 574 | int ret; | 545 | int ret; |
| @@ -675,42 +646,3 @@ static void ft_send_cmd(struct ft_cmd *cmd) | |||
| 675 | err: | 646 | err: |
| 676 | ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); | 647 | ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); |
| 677 | } | 648 | } |
| 678 | |||
| 679 | /* | ||
| 680 | * Handle request in the command thread. | ||
| 681 | */ | ||
| 682 | static void ft_exec_req(struct ft_cmd *cmd) | ||
| 683 | { | ||
| 684 | pr_debug("cmd state %x\n", cmd->state); | ||
| 685 | switch (cmd->state) { | ||
| 686 | case FC_CMD_ST_NEW: | ||
| 687 | ft_send_cmd(cmd); | ||
| 688 | break; | ||
| 689 | default: | ||
| 690 | break; | ||
| 691 | } | ||
| 692 | } | ||
| 693 | |||
| 694 | /* | ||
| 695 | * Processing thread. | ||
| 696 | * Currently one thread per tpg. | ||
| 697 | */ | ||
| 698 | int ft_thread(void *arg) | ||
| 699 | { | ||
| 700 | struct ft_tpg *tpg = arg; | ||
| 701 | struct se_queue_obj *qobj = &tpg->qobj; | ||
| 702 | struct ft_cmd *cmd; | ||
| 703 | |||
| 704 | while (!kthread_should_stop()) { | ||
| 705 | schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); | ||
| 706 | if (kthread_should_stop()) | ||
| 707 | goto out; | ||
| 708 | |||
| 709 | cmd = ft_dequeue_cmd(qobj); | ||
| 710 | if (cmd) | ||
| 711 | ft_exec_req(cmd); | ||
| 712 | } | ||
| 713 | |||
| 714 | out: | ||
| 715 | return 0; | ||
| 716 | } | ||
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index b15879d43e22..8fa39b74f22c 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c | |||
| @@ -327,7 +327,6 @@ static struct se_portal_group *ft_add_tpg( | |||
| 327 | tpg->index = index; | 327 | tpg->index = index; |
| 328 | tpg->lport_acl = lacl; | 328 | tpg->lport_acl = lacl; |
| 329 | INIT_LIST_HEAD(&tpg->lun_list); | 329 | INIT_LIST_HEAD(&tpg->lun_list); |
| 330 | transport_init_queue_obj(&tpg->qobj); | ||
| 331 | 330 | ||
| 332 | ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, | 331 | ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, |
| 333 | tpg, TRANSPORT_TPG_TYPE_NORMAL); | 332 | tpg, TRANSPORT_TPG_TYPE_NORMAL); |
| @@ -336,8 +335,8 @@ static struct se_portal_group *ft_add_tpg( | |||
| 336 | return NULL; | 335 | return NULL; |
| 337 | } | 336 | } |
| 338 | 337 | ||
| 339 | tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); | 338 | tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1); |
| 340 | if (IS_ERR(tpg->thread)) { | 339 | if (!tpg->workqueue) { |
| 341 | kfree(tpg); | 340 | kfree(tpg); |
| 342 | return NULL; | 341 | return NULL; |
| 343 | } | 342 | } |
| @@ -356,7 +355,7 @@ static void ft_del_tpg(struct se_portal_group *se_tpg) | |||
| 356 | pr_debug("del tpg %s\n", | 355 | pr_debug("del tpg %s\n", |
| 357 | config_item_name(&tpg->se_tpg.tpg_group.cg_item)); | 356 | config_item_name(&tpg->se_tpg.tpg_group.cg_item)); |
| 358 | 357 | ||
| 359 | kthread_stop(tpg->thread); | 358 | destroy_workqueue(tpg->workqueue); |
| 360 | 359 | ||
| 361 | /* Wait for sessions to be freed thru RCU, for BUG_ON below */ | 360 | /* Wait for sessions to be freed thru RCU, for BUG_ON below */ |
| 362 | synchronize_rcu(); | 361 | synchronize_rcu(); |
