diff options
Diffstat (limited to 'drivers/target/tcm_fc/tfc_cmd.c')
| -rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 447 |
1 files changed, 158 insertions, 289 deletions
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index b2a106729d4..be0c0d08c56 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -19,8 +19,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> -#include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> #include <linux/slab.h> @@ -30,6 +28,7 @@ #include <linux/configfs.h> #include <linux/ctype.h> #include <linux/hash.h> +#include <linux/percpu_ida.h> #include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -40,13 +39,8 @@ #include <scsi/fc_encode.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include <target/target_core_base.h> -#include <target/target_core_tmr.h> #include <target/configfs_macros.h> #include "tcm_fc.h" @@ -54,90 +48,60 @@ /* * Dump cmd state for debugging. */ -void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) +static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller) { struct fc_exch *ep; struct fc_seq *sp; struct se_cmd *se_cmd; - struct se_mem *mem; - struct se_transport_task *task; - - if (!(ft_debug_logging & FT_DEBUG_IO)) - return; + struct scatterlist *sg; + int count; se_cmd = &cmd->se_cmd; - printk(KERN_INFO "%s: cmd %p state %d sess %p seq %p se_cmd %p\n", - caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); - printk(KERN_INFO "%s: cmd %p cdb %p\n", - caller, cmd, cmd->cdb); - printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun); - - task = T_TASK(se_cmd); - printk(KERN_INFO "%s: cmd %p task %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n", - caller, cmd, task, task->t_tasks_se_num, - task->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags); - if (task->t_mem_list) - list_for_each_entry(mem, task->t_mem_list, se_list) - printk(KERN_INFO "%s: cmd %p mem %p page %p " - "len 0x%x off 0x%x\n", - caller, cmd, mem, - mem->se_page, mem->se_len, mem->se_off); + pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", + caller, cmd, cmd->sess, cmd->seq, se_cmd); + + pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n", + caller, cmd, se_cmd->t_data_nents, + se_cmd->data_length, se_cmd->se_cmd_flags); + + for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count) + pr_debug("%s: cmd %p sg %p page %p " + "len 0x%x off 0x%x\n", + caller, cmd, sg, + sg_page(sg), sg->length, sg->offset); + sp = cmd->seq; if (sp) { ep = fc_seq_exch(sp); - printk(KERN_INFO "%s: cmd %p sid %x did %x " + pr_debug("%s: cmd %p sid %x did %x " "ox_id %x rx_id %x seq_id %x e_stat %x\n", caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, sp->id, ep->esb_stat); } - print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE, - 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); } -static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) -{ - struct se_queue_obj *qobj; - unsigned long flags; - - qobj = &sess->tport->tpg->qobj; - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - atomic_inc(&qobj->queue_cnt); - wake_up_interruptible(&qobj->thread_wq); -} - -static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) +void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) { - unsigned long flags; - struct se_queue_req *qr; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (list_empty(&qobj->qobj_list)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return NULL; - } - qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); - list_del(&qr->qr_list); - atomic_dec(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return container_of(qr, struct ft_cmd, se_req); + if (unlikely(ft_debug_logging)) + _ft_dump_cmd(cmd, caller); } static void ft_free_cmd(struct ft_cmd *cmd) { struct fc_frame *fp; struct fc_lport *lport; + struct ft_sess *sess; if (!cmd) return; + sess = cmd->sess; fp = cmd->req_frame; lport = fr_dev(fp); if (fr_seq(fp)) lport->tt.seq_release(fr_seq(fp)); fc_frame_free(fp); - ft_sess_put(cmd->sess); /* undo get from lookup at recv */ - kfree(cmd); + percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); + ft_sess_put(sess); /* undo get from lookup at recv */ } void ft_release_cmd(struct se_cmd *se_cmd) @@ -147,9 +111,10 @@ void ft_release_cmd(struct se_cmd *se_cmd) ft_free_cmd(cmd); } -void ft_check_stop_free(struct se_cmd *se_cmd) +int ft_check_stop_free(struct se_cmd *se_cmd) { - transport_generic_free_cmd(se_cmd, 0, 1, 0); + transport_generic_free_cmd(se_cmd, 0); + return 1; } /* @@ -163,16 +128,20 @@ int ft_queue_status(struct se_cmd *se_cmd) struct fc_lport *lport; struct fc_exch *ep; size_t len; + int rc; + if (cmd->aborted) + return 0; ft_dump_cmd(cmd, __func__); ep = fc_seq_exch(cmd->seq); lport = ep->lp; len = sizeof(*fcp) + se_cmd->scsi_sense_length; fp = fc_frame_alloc(lport, len); if (!fp) { - /* XXX shouldn't just drop it - requeue and retry? */ - return 0; + se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; + return -ENOMEM; } + fcp = fc_frame_payload_get(fp, len); memset(fcp, 0, len); fcp->resp.fr_status = se_cmd->scsi_status; @@ -203,7 +172,18 @@ int ft_queue_status(struct se_cmd *se_cmd) fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); - lport->tt.seq_send(lport, cmd->seq, fp); + rc = lport->tt.seq_send(lport, cmd->seq, fp); + if (rc) { + pr_info_ratelimited("%s: Failed to send response frame %p, " + "xid <0x%x>\n", __func__, fp, ep->xid); + /* + * Generate a TASK_SET_FULL status to notify the initiator + * to reduce it's queue_depth after the se_cmd response has + * been re-queued by target-core. + */ + se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; + return -ENOMEM; + } lport->tt.exch_done(cmd->seq); return 0; } @@ -230,11 +210,13 @@ int ft_write_pending(struct se_cmd *se_cmd) ft_dump_cmd(cmd, __func__); + if (cmd->aborted) + return 0; ep = fc_seq_exch(cmd->seq); lport = ep->lp; fp = fc_frame_alloc(lport, sizeof(*txrdy)); if (!fp) - return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + return -ENOMEM; /* Signal QUEUE_FULL */ txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); memset(txrdy, 0, sizeof(*txrdy)); @@ -254,20 +236,10 @@ int ft_write_pending(struct se_cmd *se_cmd) */ if ((ep->xid <= lport->lro_xid) && (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { - if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - /* - * Map se_mem list to scatterlist, so that - * DDP can be setup. DDP setup function require - * scatterlist. se_mem_list is internal to - * TCM/LIO target - */ - transport_do_task_sg_chain(se_cmd); - cmd->sg = T_TASK(se_cmd)->t_tasks_sg_chained; - cmd->sg_cnt = - T_TASK(se_cmd)->t_tasks_sg_chained_no; - } - if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, - cmd->sg, cmd->sg_cnt)) + if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && + lport->tt.ddp_target(lport, ep->xid, + se_cmd->t_data_sg, + se_cmd->t_data_nents)) cmd->was_ddp_setup = 1; } } @@ -279,25 +251,14 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + if (cmd->aborted) + return ~0; return fc_seq_exch(cmd->seq)->rxid; } int ft_get_cmd_state(struct se_cmd *se_cmd) { - struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); - - return cmd->state; -} - -int ft_is_state_remove(struct se_cmd *se_cmd) -{ - return 0; /* XXX TBD */ -} - -void ft_new_cmd_failure(struct se_cmd *se_cmd) -{ - /* XXX TBD */ - printk(KERN_INFO "%s: se_cmd %p\n", __func__, se_cmd); + return 0; } /* @@ -308,11 +269,10 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) struct ft_cmd *cmd = arg; struct fc_frame_header *fh; - if (IS_ERR(fp)) { + if (unlikely(IS_ERR(fp))) { /* XXX need to find cmd if queued */ - cmd->se_cmd.t_state = TRANSPORT_REMOVE; cmd->seq = NULL; - transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + cmd->aborted = true; return; } @@ -326,10 +286,11 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) case FC_RCTL_DD_SOL_CTL: /* transfer ready */ case FC_RCTL_DD_DATA_DESC: /* transfer ready */ default: - printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + pr_debug("%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); + ft_invl_hw_context(cmd); fc_frame_free(fp); - transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0); break; } } @@ -351,7 +312,7 @@ static void ft_send_resp_status(struct fc_lport *lport, struct fcp_resp_rsp_info *info; fh = fc_frame_header_get(rx_fp); - FT_IO_DBG("FCP error response: did %x oxid %x status %x code %x\n", + pr_debug("FCP error response: did %x oxid %x status %x code %x\n", ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code); len = sizeof(*fcp); if (status == SAM_STAT_GOOD) @@ -371,20 +332,33 @@ static void ft_send_resp_status(struct fc_lport *lport, fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); sp = fr_seq(fp); - if (sp) + if (sp) { lport->tt.seq_send(lport, sp, fp); - else + lport->tt.exch_done(sp); + } else { lport->tt.frame_send(lport, fp); + } } /* * Send error or task management response. - * Always frees the cmd and associated state. */ -static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) +static void ft_send_resp_code(struct ft_cmd *cmd, + enum fcp_resp_rsp_codes code) { ft_send_resp_status(cmd->sess->tport->lport, cmd->req_frame, SAM_STAT_GOOD, code); +} + + +/* + * Send error or task management response. + * Always frees the cmd and associated state. + */ +static void ft_send_resp_code_and_free(struct ft_cmd *cmd, + enum fcp_resp_rsp_codes code) +{ + ft_send_resp_code(cmd, code); ft_free_cmd(cmd); } @@ -393,9 +367,8 @@ static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) */ static void ft_send_tm(struct ft_cmd *cmd) { - struct se_tmr_req *tmr; struct fcp_cmnd *fcp; - struct ft_sess *sess; + int rc; u8 tm_func; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); @@ -421,61 +394,30 @@ static void ft_send_tm(struct ft_cmd *cmd) * FCP4r01 indicates having a combination of * tm_flags set is invalid. */ - FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); - ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); + pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); + ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); return; } - FT_TM_DBG("alloc tm cmd fn %d\n", tm_func); - tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); - if (!tmr) { - FT_TM_DBG("alloc failed\n"); - ft_send_resp_code(cmd, FCP_TMF_FAILED); - return; - } - cmd->se_cmd.se_tmr_req = tmr; - - switch (fcp->fc_tm_flags) { - case FCP_TMF_LUN_RESET: - cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); - if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) { - /* - * Make sure to clean up newly allocated TMR request - * since "unable to handle TMR request because failed - * to get to LUN" - */ - FT_TM_DBG("Failed to get LUN for TMR func %d, " - "se_cmd %p, unpacked_lun %d\n", - tm_func, &cmd->se_cmd, cmd->lun); - ft_dump_cmd(cmd, __func__); - sess = cmd->sess; - transport_send_check_condition_and_sense(&cmd->se_cmd, - cmd->se_cmd.scsi_sense_reason, 0); - transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); - ft_sess_put(sess); - return; - } - break; - case FCP_TMF_TGT_RESET: - case FCP_TMF_CLR_TASK_SET: - case FCP_TMF_ABT_TASK_SET: - case FCP_TMF_CLR_ACA: - break; - default: - return; - } - transport_generic_handle_tmr(&cmd->se_cmd); + /* FIXME: Add referenced task tag for ABORT_TASK */ + rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + cmd, tm_func, GFP_KERNEL, 0, 0); + if (rc < 0) + ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); } /* * Send status from completed task management request. */ -int ft_queue_tm_resp(struct se_cmd *se_cmd) +void ft_queue_tm_resp(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; + if (cmd->aborted) + return; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; @@ -487,20 +429,23 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) code = FCP_TMF_REJECTED; break; case TMR_TASK_DOES_NOT_EXIST: - case TMR_TASK_STILL_ALLEGIANT: - case TMR_TASK_FAILOVER_NOT_SUPPORTED: case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: - case TMR_FUNCTION_AUTHORIZATION_FAILED: default: code = FCP_TMF_FAILED; break; } - FT_TM_DBG("tmr fn %d resp %d fcp code %d\n", + pr_debug("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); - return 0; } +void ft_aborted_task(struct se_cmd *se_cmd) +{ + return; +} + +static void ft_send_work(struct work_struct *work); + /* * Handle incoming FCP command. */ @@ -508,22 +453,31 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) { struct ft_cmd *cmd; struct fc_lport *lport = sess->tport->lport; + struct se_session *se_sess = sess->se_sess; + int tag; - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); - if (!cmd) + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + if (tag < 0) goto busy; + + cmd = &((struct ft_cmd *)se_sess->sess_cmd_map)[tag]; + memset(cmd, 0, sizeof(struct ft_cmd)); + + cmd->se_cmd.map_tag = tag; cmd->sess = sess; cmd->seq = lport->tt.seq_assign(lport, fp); if (!cmd->seq) { - kfree(cmd); + percpu_ida_free(&se_sess->sess_tag_pool, tag); goto busy; } cmd->req_frame = fp; /* hold frame during cmd */ - ft_queue_cmd(sess, cmd); + + INIT_WORK(&cmd->work, ft_send_work); + queue_work(sess->tport->tpg->workqueue, &cmd->work); return; busy: - FT_IO_DBG("cmd or seq allocation failure - sending BUSY\n"); + pr_debug("cmd or seq allocation failure - sending BUSY\n"); ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0); fc_frame_free(fp); ft_sess_put(sess); /* undo get from lookup */ @@ -548,7 +502,7 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) case FC_RCTL_DD_DATA_DESC: /* transfer ready */ case FC_RCTL_ELS4_REQ: /* SRR, perhaps */ default: - printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + pr_debug("%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); fc_frame_free(fp); ft_sess_put(sess); /* undo get from lookup */ @@ -559,15 +513,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) /* * Send new command to target. */ -static void ft_send_cmd(struct ft_cmd *cmd) +static void ft_send_work(struct work_struct *work) { + struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); - struct se_cmd *se_cmd; struct fcp_cmnd *fcp; - int data_dir; - u32 data_len; + int data_dir = 0; int task_attr; - int ret; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); if (!fcp) @@ -576,56 +528,6 @@ static void ft_send_cmd(struct ft_cmd *cmd) if (fcp->fc_flags & FCP_CFL_LEN_MASK) goto err; /* not handling longer CDBs yet */ - if (fcp->fc_tm_flags) { - task_attr = FCP_PTA_SIMPLE; - data_dir = DMA_NONE; - data_len = 0; - } else { - switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { - case 0: - data_dir = DMA_NONE; - break; - case FCP_CFL_RDDATA: - data_dir = DMA_FROM_DEVICE; - break; - case FCP_CFL_WRDATA: - data_dir = DMA_TO_DEVICE; - break; - case FCP_CFL_WRDATA | FCP_CFL_RDDATA: - goto err; /* TBD not supported by tcm_fc yet */ - } - /* - * Locate the SAM Task Attr from fc_pri_ta - */ - switch (fcp->fc_pri_ta & FCP_PTA_MASK) { - case FCP_PTA_HEADQ: - task_attr = MSG_HEAD_TAG; - break; - case FCP_PTA_ORDERED: - task_attr = MSG_ORDERED_TAG; - break; - case FCP_PTA_ACA: - task_attr = MSG_ACA_TAG; - break; - case FCP_PTA_SIMPLE: /* Fallthrough */ - default: - task_attr = MSG_SIMPLE_TAG; - } - - - task_attr = fcp->fc_pri_ta & FCP_PTA_MASK; - data_len = ntohl(fcp->fc_dl); - cmd->cdb = fcp->fc_cdb; - } - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod - * infrastructure - */ - transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, - data_len, data_dir, task_attr, - &cmd->ft_sense_buffer[0]); /* * Check for FCP task management flags */ @@ -634,83 +536,50 @@ static void ft_send_cmd(struct ft_cmd *cmd) return; } - fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); - - cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); - ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun); - if (ret < 0) { - ft_dump_cmd(cmd, __func__); - transport_send_check_condition_and_sense(&cmd->se_cmd, - cmd->se_cmd.scsi_sense_reason, 0); - return; - } - - ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); - - FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); - ft_dump_cmd(cmd, __func__); - - if (ret == -1) { - transport_send_check_condition_and_sense(se_cmd, - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); - transport_generic_free_cmd(se_cmd, 0, 1, 0); - return; - } - if (ret == -2) { - if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) - ft_queue_status(se_cmd); - else - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - transport_generic_free_cmd(se_cmd, 0, 1, 0); - return; + switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { + case 0: + data_dir = DMA_NONE; + break; + case FCP_CFL_RDDATA: + data_dir = DMA_FROM_DEVICE; + break; + case FCP_CFL_WRDATA: + data_dir = DMA_TO_DEVICE; + break; + case FCP_CFL_WRDATA | FCP_CFL_RDDATA: + goto err; /* TBD not supported by tcm_fc yet */ } - transport_generic_handle_cdb(se_cmd); - return; - -err: - ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); - return; -} - -/* - * Handle request in the command thread. - */ -static void ft_exec_req(struct ft_cmd *cmd) -{ - FT_IO_DBG("cmd state %x\n", cmd->state); - switch (cmd->state) { - case FC_CMD_ST_NEW: - ft_send_cmd(cmd); + /* + * Locate the SAM Task Attr from fc_pri_ta + */ + switch (fcp->fc_pri_ta & FCP_PTA_MASK) { + case FCP_PTA_HEADQ: + task_attr = MSG_HEAD_TAG; break; - default: + case FCP_PTA_ORDERED: + task_attr = MSG_ORDERED_TAG; break; + case FCP_PTA_ACA: + task_attr = MSG_ACA_TAG; + break; + case FCP_PTA_SIMPLE: /* Fallthrough */ + default: + task_attr = MSG_SIMPLE_TAG; } -} -/* - * Processing thread. - * Currently one thread per tpg. - */ -int ft_thread(void *arg) -{ - struct ft_tpg *tpg = arg; - struct se_queue_obj *qobj = &tpg->qobj; - struct ft_cmd *cmd; - int ret; - - set_user_nice(current, -20); - - while (!kthread_should_stop()) { - ret = wait_event_interruptible(qobj->thread_wq, - atomic_read(&qobj->queue_cnt) || kthread_should_stop()); - if (ret < 0 || kthread_should_stop()) - goto out; - cmd = ft_dequeue_cmd(qobj); - if (cmd) - ft_exec_req(cmd); - } + fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); + /* + * Use a single se_cmd->cmd_kref as we expect to release se_cmd + * directly from ft_check_stop_free callback in response path. + */ + if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + ntohl(fcp->fc_dl), task_attr, data_dir, 0)) + goto err; -out: - return 0; + pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); + return; + +err: + ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); } |
