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>
This commit is contained in:
parent
7481deb413
commit
a636078552
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue