aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2011-11-18 23:36:22 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2011-12-14 06:40:56 -0500
commita63607855224702ea17e6016ecf3f7d544e83625 (patch)
tree844d9a7dbdc636ba657763f04945b91ca8da9ba7
parent7481deb413be132a22193e8a0bce88b311ecb3c2 (diff)
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.c86
-rw-r--r--include/target/target_core_base.h5
-rw-r--r--include/target/target_core_fabric.h4
3 files changed, 92 insertions, 3 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 176f956665e..e4389d40c05 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1642,6 +1642,80 @@ int transport_handle_cdb_direct(
1642} 1642}
1643EXPORT_SYMBOL(transport_handle_cdb_direct); 1643EXPORT_SYMBOL(transport_handle_cdb_direct);
1644 1644
1645/**
1646 * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd
1647 *
1648 * @se_cmd: command descriptor to submit
1649 * @se_sess: associated se_sess for endpoint
1650 * @cdb: pointer to SCSI CDB
1651 * @sense: pointer to SCSI sense buffer
1652 * @unpacked_lun: unpacked LUN to reference for struct se_lun
1653 * @data_length: fabric expected data transfer length
1654 * @task_addr: SAM task attribute
1655 * @data_dir: DMA data direction
1656 * @flags: flags for command submission from target_sc_flags_tables
1657 *
1658 * This may only be called from process context, and also currently
1659 * assumes internal allocation of fabric payload buffer by target-core.
1660 **/
1661int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
1662 unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
1663 u32 data_length, int task_attr, int data_dir, int flags)
1664{
1665 struct se_portal_group *se_tpg;
1666 int rc;
1667
1668 se_tpg = se_sess->se_tpg;
1669 BUG_ON(!se_tpg);
1670 BUG_ON(se_cmd->se_tfo || se_cmd->se_sess);
1671 BUG_ON(in_interrupt());
1672 /*
1673 * Initialize se_cmd for target operation. From this point
1674 * exceptions are handled by sending exception status via
1675 * target_core_fabric_ops->queue_status() callback
1676 */
1677 transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
1678 data_length, data_dir, task_attr, sense);
1679 /*
1680 * Obtain struct se_cmd->cmd_kref reference and add new cmd to
1681 * se_sess->sess_cmd_list. A second kref_get here is necessary
1682 * for fabrics using TARGET_SCF_ACK_KREF that expect a second
1683 * kref_put() to happen during fabric packet acknowledgement.
1684 */
1685 target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
1686 /*
1687 * Signal bidirectional data payloads to target-core
1688 */
1689 if (flags & TARGET_SCF_BIDI_OP)
1690 se_cmd->se_cmd_flags |= SCF_BIDI;
1691 /*
1692 * Locate se_lun pointer and attach it to struct se_cmd
1693 */
1694 if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0)
1695 goto out_check_cond;
1696 /*
1697 * Sanitize CDBs via transport_generic_cmd_sequencer() and
1698 * allocate the necessary tasks to complete the received CDB+data
1699 */
1700 rc = transport_generic_allocate_tasks(se_cmd, cdb);
1701 if (rc != 0)
1702 goto out_check_cond;
1703 /*
1704 * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend
1705 * for immediate execution of READs, otherwise wait for
1706 * transport_generic_handle_data() to be called for WRITEs
1707 * when fabric has filled the incoming buffer.
1708 */
1709 transport_handle_cdb_direct(se_cmd);
1710 return 0;
1711
1712out_check_cond:
1713 transport_send_check_condition_and_sense(se_cmd,
1714 se_cmd->scsi_sense_reason, 0);
1715 return 0;
1716}
1717EXPORT_SYMBOL(target_submit_cmd);
1718
1645/* 1719/*
1646 * Used by fabric module frontends defining a TFO->new_cmd_map() caller 1720 * Used by fabric module frontends defining a TFO->new_cmd_map() caller
1647 * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to 1721 * 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);
3910/* target_get_sess_cmd - Add command to active ->sess_cmd_list 3984/* target_get_sess_cmd - Add command to active ->sess_cmd_list
3911 * @se_sess: session to reference 3985 * @se_sess: session to reference
3912 * @se_cmd: command descriptor to add 3986 * @se_cmd: command descriptor to add
3987 * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd()
3913 */ 3988 */
3914void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) 3989void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
3990 bool ack_kref)
3915{ 3991{
3916 unsigned long flags; 3992 unsigned long flags;
3917 3993
3918 kref_init(&se_cmd->cmd_kref); 3994 kref_init(&se_cmd->cmd_kref);
3919 kref_get(&se_cmd->cmd_kref); 3995 /*
3996 * Add a second kref if the fabric caller is expecting to handle
3997 * fabric acknowledgement that requires two target_put_sess_cmd()
3998 * invocations before se_cmd descriptor release.
3999 */
4000 if (ack_kref == true)
4001 kref_get(&se_cmd->cmd_kref);
3920 4002
3921 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); 4003 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
3922 list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); 4004 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 af088a9e490..28190dc10ee 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -226,6 +226,11 @@ enum tcm_sense_reason_table {
226 TCM_RESERVATION_CONFLICT = 0x10, 226 TCM_RESERVATION_CONFLICT = 0x10,
227}; 227};
228 228
229enum target_sc_flags_table {
230 TARGET_SCF_BIDI_OP = 0x01,
231 TARGET_SCF_ACK_KREF = 0x02,
232};
233
229/* fabric independent task management function values */ 234/* fabric independent task management function values */
230enum tcm_tmreq_table { 235enum tcm_tmreq_table {
231 TMR_ABORT_TASK = 1, 236 TMR_ABORT_TASK = 1,
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index d035d865dbe..aaa26da5a52 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 *,
118 struct se_session *, u32, int, int, unsigned char *); 118 struct se_session *, u32, int, int, unsigned char *);
119int transport_lookup_cmd_lun(struct se_cmd *, u32); 119int transport_lookup_cmd_lun(struct se_cmd *, u32);
120int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); 120int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
121int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
122 unsigned char *, u32, u32, int, int, int);
121int transport_handle_cdb_direct(struct se_cmd *); 123int transport_handle_cdb_direct(struct se_cmd *);
122int transport_generic_handle_cdb_map(struct se_cmd *); 124int transport_generic_handle_cdb_map(struct se_cmd *);
123int transport_generic_handle_data(struct se_cmd *); 125int transport_generic_handle_data(struct se_cmd *);
@@ -134,7 +136,7 @@ bool transport_wait_for_tasks(struct se_cmd *);
134int transport_check_aborted_status(struct se_cmd *, int); 136int transport_check_aborted_status(struct se_cmd *, int);
135int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); 137int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
136 138
137void target_get_sess_cmd(struct se_session *, struct se_cmd *); 139void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);
138int target_put_sess_cmd(struct se_session *, struct se_cmd *); 140int target_put_sess_cmd(struct se_session *, struct se_cmd *);
139void target_splice_sess_cmd_list(struct se_session *); 141void target_splice_sess_cmd_list(struct se_session *);
140void target_wait_for_sess_cmds(struct se_session *, int); 142void target_wait_for_sess_cmds(struct se_session *, int);