diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-11-18 20:36:22 -0800 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-12-14 11:40:56 +0000 |
commit | a63607855224702ea17e6016ecf3f7d544e83625 (patch) | |
tree | 844d9a7dbdc636ba657763f04945b91ca8da9ba7 | |
parent | 7481deb413be132a22193e8a0bce88b311ecb3c2 (diff) | |
download | linux-a63607855224702ea17e6016ecf3f7d544e83625.tar.bz2 |
target: Add target_submit_cmd() for process context fabric submission
This patch adds a target_submit_cmd() caller that can be used by fabrics
to submit an uninitialized se_cmd descriptor to an struct se_session +
unpacked_lun from workqueue process context. This call will invoke the
following steps:
- transport_init_se_cmd() to setup se_cmd specific pointers
- Obtain se_cmd->cmd_kref references with target_get_sess_cmd()
- set se_cmd->t_tasks_bidi
- transport_lookup_cmd_lun() to setup struct se_cmd->se_lun from
the passed unpacked_lun
- transport_generic_allocate_tasks() to setup the passed *cdb, and
- transport_handle_cdb_direct() handle READ dispatch or WRITE
ready-to-transfer callback to fabric
v2 changes from hch feedback:
*) Add target_sc_flags_table for target_submit_cmd flags
*) Rename bidi parameter to flags, add TARGET_SCF_BIDI_OP
*) Convert checks to BUG_ON
*) Add out_check_cond for transport_send_check_condition_and_sense
usage
v3 changes:
*) Add TARGET_SCF_ACK_KREF for target_submit_cmd into
target_get_sess_cmd to determine when the fabric caller is expecting
a second kref_put() from fabric packet acknowledgement.
Cc: Christoph Hellwig <hch@lst.de>
Cc: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_transport.c | 86 | ||||
-rw-r--r-- | include/target/target_core_base.h | 5 | ||||
-rw-r--r-- | include/target/target_core_fabric.h | 4 |
3 files changed, 92 insertions, 3 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 176f956665e8..e4389d40c057 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1642,6 +1642,80 @@ int transport_handle_cdb_direct( } EXPORT_SYMBOL(transport_handle_cdb_direct); +/** + * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd + * + * @se_cmd: command descriptor to submit + * @se_sess: associated se_sess for endpoint + * @cdb: pointer to SCSI CDB + * @sense: pointer to SCSI sense buffer + * @unpacked_lun: unpacked LUN to reference for struct se_lun + * @data_length: fabric expected data transfer length + * @task_addr: SAM task attribute + * @data_dir: DMA data direction + * @flags: flags for command submission from target_sc_flags_tables + * + * This may only be called from process context, and also currently + * assumes internal allocation of fabric payload buffer by target-core. + **/ +int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, + unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, + u32 data_length, int task_attr, int data_dir, int flags) +{ + struct se_portal_group *se_tpg; + int rc; + + se_tpg = se_sess->se_tpg; + BUG_ON(!se_tpg); + BUG_ON(se_cmd->se_tfo || se_cmd->se_sess); + BUG_ON(in_interrupt()); + /* + * Initialize se_cmd for target operation. From this point + * exceptions are handled by sending exception status via + * target_core_fabric_ops->queue_status() callback + */ + transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, + data_length, data_dir, task_attr, sense); + /* + * Obtain struct se_cmd->cmd_kref reference and add new cmd to + * se_sess->sess_cmd_list. A second kref_get here is necessary + * for fabrics using TARGET_SCF_ACK_KREF that expect a second + * kref_put() to happen during fabric packet acknowledgement. + */ + target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + /* + * Signal bidirectional data payloads to target-core + */ + if (flags & TARGET_SCF_BIDI_OP) + se_cmd->se_cmd_flags |= SCF_BIDI; + /* + * Locate se_lun pointer and attach it to struct se_cmd + */ + if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0) + goto out_check_cond; + /* + * Sanitize CDBs via transport_generic_cmd_sequencer() and + * allocate the necessary tasks to complete the received CDB+data + */ + rc = transport_generic_allocate_tasks(se_cmd, cdb); + if (rc != 0) + goto out_check_cond; + /* + * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend + * for immediate execution of READs, otherwise wait for + * transport_generic_handle_data() to be called for WRITEs + * when fabric has filled the incoming buffer. + */ + transport_handle_cdb_direct(se_cmd); + return 0; + +out_check_cond: + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + return 0; +} +EXPORT_SYMBOL(target_submit_cmd); + /* * Used by fabric module frontends defining a TFO->new_cmd_map() caller * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to @@ -3910,13 +3984,21 @@ EXPORT_SYMBOL(transport_generic_free_cmd); /* target_get_sess_cmd - Add command to active ->sess_cmd_list * @se_sess: session to reference * @se_cmd: command descriptor to add + * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; kref_init(&se_cmd->cmd_kref); - kref_get(&se_cmd->cmd_kref); + /* + * Add a second kref if the fabric caller is expecting to handle + * fabric acknowledgement that requires two target_put_sess_cmd() + * invocations before se_cmd descriptor release. + */ + if (ack_kref == true) + kref_get(&se_cmd->cmd_kref); spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index af088a9e4905..28190dc10eef 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -226,6 +226,11 @@ enum tcm_sense_reason_table { TCM_RESERVATION_CONFLICT = 0x10, }; +enum target_sc_flags_table { + TARGET_SCF_BIDI_OP = 0x01, + TARGET_SCF_ACK_KREF = 0x02, +}; + /* fabric independent task management function values */ enum tcm_tmreq_table { TMR_ABORT_TASK = 1, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index d035d865dbef..aaa26da5a527 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -118,6 +118,8 @@ void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); int transport_lookup_cmd_lun(struct se_cmd *, u32); int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); +int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, + unsigned char *, u32, u32, int, int, int); int transport_handle_cdb_direct(struct se_cmd *); int transport_generic_handle_cdb_map(struct se_cmd *); int transport_generic_handle_data(struct se_cmd *); @@ -134,7 +136,7 @@ bool transport_wait_for_tasks(struct se_cmd *); int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); -void target_get_sess_cmd(struct se_session *, struct se_cmd *); +void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); int target_put_sess_cmd(struct se_session *, struct se_cmd *); void target_splice_sess_cmd_list(struct se_session *); void target_wait_for_sess_cmds(struct se_session *, int); |