summaryrefslogtreecommitdiff
path: root/drivers/target
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/Makefile1
-rw-r--r--drivers/target/iscsi/iscsi_target.c51
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c34
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c49
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_stat.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c20
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h1
-rw-r--r--drivers/target/loopback/tcm_loop.c41
-rw-r--r--drivers/target/target_core_alua.c33
-rw-r--r--drivers/target/target_core_alua.h4
-rw-r--r--drivers/target/target_core_cdb.c293
-rw-r--r--drivers/target/target_core_cdb.h14
-rw-r--r--drivers/target/target_core_configfs.c16
-rw-r--r--drivers/target/target_core_device.c85
-rw-r--r--drivers/target/target_core_fabric_configfs.c1
-rw-r--r--drivers/target/target_core_fabric_lib.c13
-rw-r--r--drivers/target/target_core_file.c57
-rw-r--r--drivers/target/target_core_file.h4
-rw-r--r--drivers/target/target_core_hba.c1
-rw-r--r--drivers/target/target_core_iblock.c275
-rw-r--r--drivers/target/target_core_iblock.h2
-rw-r--r--drivers/target/target_core_pr.c350
-rw-r--r--drivers/target/target_core_pr.h7
-rw-r--r--drivers/target/target_core_pscsi.c262
-rw-r--r--drivers/target/target_core_pscsi.h1
-rw-r--r--drivers/target/target_core_rd.c19
-rw-r--r--drivers/target/target_core_rd.h2
-rw-r--r--drivers/target/target_core_scdb.c105
-rw-r--r--drivers/target/target_core_scdb.h10
-rw-r--r--drivers/target/target_core_stat.c1
-rw-r--r--drivers/target/target_core_tmr.c239
-rw-r--r--drivers/target/target_core_tpg.c3
-rw-r--r--drivers/target/target_core_transport.c1800
-rw-r--r--drivers/target/target_core_ua.c1
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h2
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c21
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c13
-rw-r--r--drivers/target/tcm_fc/tfc_io.c1
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c1
43 files changed, 1474 insertions, 2373 deletions
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 1060c7b7f803..62e54053bcd8 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -6,7 +6,6 @@ target_core_mod-y := target_core_configfs.o \
target_core_hba.o \
target_core_pr.o \
target_core_alua.o \
- target_core_scdb.o \
target_core_tmr.o \
target_core_tpg.o \
target_core_transport.o \
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 6a4ea29c2f36..0fd96c10271d 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -22,6 +22,7 @@
#include <linux/kthread.h>
#include <linux/crypto.h>
#include <linux/completion.h>
+#include <linux/module.h>
#include <asm/unaligned.h>
#include <scsi/scsi_device.h>
#include <scsi/iscsi_proto.h>
@@ -765,7 +766,7 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 :
cmd->se_cmd.t_data_nents;
- iov_count += TRANSPORT_IOV_DATA_BUFFER;
+ iov_count += ISCSI_IOV_DATA_BUFFER;
cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL);
if (!cmd->iov_data) {
@@ -1079,7 +1080,9 @@ attach_cmd:
*/
if (!cmd->immediate_data) {
cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+ return 0;
+ else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, buf, cmd);
@@ -1819,17 +1822,16 @@ attach:
int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
out_of_order_cmdsn = 1;
- else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+ else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
return 0;
- } else { /* (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) */
+ else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, buf, cmd);
- }
}
iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
- if (out_of_order_cmdsn)
+ if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE))
return 0;
/*
* Found the referenced task, send to transport for processing.
@@ -3538,16 +3540,8 @@ get_immediate:
spin_lock_bh(&conn->cmd_lock);
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
- /*
- * Determine if a struct se_cmd is assoicated with
- * this struct iscsi_cmd.
- */
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
- !(cmd->tmr_req))
- iscsit_release_cmd(cmd);
- else
- transport_generic_free_cmd(&cmd->se_cmd,
- 1, 0);
+
+ iscsit_free_cmd(cmd);
goto get_immediate;
case ISTATE_SEND_NOPIN_WANT_RESPONSE:
spin_unlock_bh(&cmd->istate_lock);
@@ -3940,7 +3934,6 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
{
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
struct iscsi_session *sess = conn->sess;
- struct se_cmd *se_cmd;
/*
* We expect this function to only ever be called from either RX or TX
* thread context via iscsit_close_connection() once the other context
@@ -3948,35 +3941,13 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
*/
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)) {
- list_del(&cmd->i_list);
- spin_unlock_bh(&conn->cmd_lock);
- iscsit_increment_maxcmdsn(cmd, sess);
- se_cmd = &cmd->se_cmd;
- /*
- * Special cases for active iSCSI TMR, and
- * transport_lookup_cmd_lun() failing from
- * iscsit_get_lun_for_cmd() in iscsit_handle_scsi_cmd().
- */
- if (cmd->tmr_req && se_cmd->transport_wait_for_tasks)
- se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
- else if (cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)
- transport_release_cmd(se_cmd);
- else
- iscsit_release_cmd(cmd);
-
- spin_lock_bh(&conn->cmd_lock);
- continue;
- }
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
iscsit_increment_maxcmdsn(cmd, sess);
- se_cmd = &cmd->se_cmd;
- if (se_cmd->transport_wait_for_tasks)
- se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
}
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index 11fd74307811..beb39469e7f1 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -18,6 +18,7 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/crypto.h>
#include <linux/err.h>
@@ -27,40 +28,11 @@
#include "iscsi_target_nego.h"
#include "iscsi_target_auth.h"
-static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2])
-{
- unsigned char result = 0;
- /*
- * MSB
- */
- if ((val[0] >= 'a') && (val[0] <= 'f'))
- result = ((val[0] - 'a' + 10) & 0xf) << 4;
- else
- if ((val[0] >= 'A') && (val[0] <= 'F'))
- result = ((val[0] - 'A' + 10) & 0xf) << 4;
- else /* digit */
- result = ((val[0] - '0') & 0xf) << 4;
- /*
- * LSB
- */
- if ((val[1] >= 'a') && (val[1] <= 'f'))
- result |= ((val[1] - 'a' + 10) & 0xf);
- else
- if ((val[1] >= 'A') && (val[1] <= 'F'))
- result |= ((val[1] - 'A' + 10) & 0xf);
- else /* digit */
- result |= ((val[1] - '0') & 0xf);
-
- return result;
-}
-
static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
{
- int i, j = 0;
+ int j = DIV_ROUND_UP(len, 2);
- for (i = 0; i < len; i += 2) {
- dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]);
- }
+ hex2bin(dst, src, j);
dst[j] = '\0';
return j;
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index f1643dbf6a92..db327845e46b 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -20,6 +20,7 @@
****************************************************************************/
#include <linux/configfs.h>
+#include <linux/export.h>
#include <target/target_core_base.h>
#include <target/target_core_transport.h>
#include <target/target_core_fabric_ops.h>
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 470ed551eeb5..3723d90d5ae5 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -57,6 +57,9 @@
#define TA_PROD_MODE_WRITE_PROTECT 0
#define TA_CACHE_CORE_NPS 0
+
+#define ISCSI_IOV_DATA_BUFFER 5
+
enum tpg_np_network_transport_table {
ISCSI_TCP = 0,
ISCSI_SCTP_TCP = 1,
@@ -425,7 +428,6 @@ struct iscsi_cmd {
/* Number of times struct iscsi_cmd is present in immediate queue */
atomic_t immed_queue_count;
atomic_t response_queue_count;
- atomic_t transport_sent;
spinlock_t datain_lock;
spinlock_t dataout_timeout_lock;
/* spinlock for protecting struct iscsi_cmd->i_state */
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 91a4d170bda4..0b8404c30125 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -143,12 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_del(&cmd->i_list);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -170,12 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_del(&cmd->i_list);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -260,12 +250,7 @@ void iscsit_discard_cr_cmds_by_expstatsn(
iscsit_remove_cmd_from_connection_recovery(cmd, sess);
spin_unlock(&cr->conn_recovery_cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 0);
+ iscsit_free_cmd(cmd);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -319,12 +304,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
}
spin_unlock_bh(&conn->cmd_lock);
@@ -377,13 +357,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
-
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 0);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
continue;
}
@@ -403,13 +377,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
(cmd->cmd_sn >= conn->sess->exp_cmd_sn)) {
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
-
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
continue;
}
@@ -434,10 +402,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
iscsit_free_all_datain_reqs(cmd);
- if ((cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
- cmd->se_cmd.transport_wait_for_tasks)
- cmd->se_cmd.transport_wait_for_tasks(&cmd->se_cmd,
- 0, 0);
+ transport_wait_for_tasks(&cmd->se_cmd);
/*
* Add the struct iscsi_cmd to the connection recovery cmd list
*/
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 4d087ac11067..426cd4bf6a9a 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -504,7 +504,7 @@ static int iscsi_target_do_authentication(
break;
case 1:
pr_debug("iSCSI security negotiation"
- " completed sucessfully.\n");
+ " completed successfully.\n");
login->auth_complete = 1;
if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) &&
(login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) {
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c
index bbdbe9301b27..f1db83077e0a 100644
--- a/drivers/target/iscsi/iscsi_target_stat.c
+++ b/drivers/target/iscsi/iscsi_target_stat.c
@@ -20,6 +20,7 @@
******************************************************************************/
#include <linux/configfs.h>
+#include <linux/export.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_transport.h>
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index db1fe1ec84df..490207eacde9 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -250,7 +250,7 @@ static int iscsit_task_reassign_complete_write(
* so if we have received all DataOUT we can safety ignore Initiator.
*/
if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
- if (!atomic_read(&cmd->transport_sent)) {
+ if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
pr_debug("WRITE ITT: 0x%08x: t_state: %d"
" never sent to transport\n",
cmd->init_task_tag, cmd->se_cmd.t_state);
@@ -314,11 +314,11 @@ static int iscsit_task_reassign_complete_read(
cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
}
- if (!atomic_read(&cmd->transport_sent)) {
+ if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
pr_debug("READ ITT: 0x%08x: t_state: %d never sent to"
" transport\n", cmd->init_task_tag,
cmd->se_cmd.t_state);
- transport_generic_handle_cdb(se_cmd);
+ transport_handle_cdb_direct(se_cmd);
return 0;
}
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index f00137f377b2..02348f727bd4 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -289,7 +289,8 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
}
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
- (void *)cmd->tmr_req, tcm_function);
+ (void *)cmd->tmr_req, tcm_function,
+ GFP_KERNEL);
if (!se_cmd->se_tmr_req)
goto out;
@@ -839,6 +840,23 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
kmem_cache_free(lio_cmd_cache, cmd);
}
+void iscsit_free_cmd(struct iscsi_cmd *cmd)
+{
+ /*
+ * Determine if a struct se_cmd is assoicated with
+ * this struct iscsi_cmd.
+ */
+ switch (cmd->iscsi_opcode) {
+ case ISCSI_OP_SCSI_CMD:
+ case ISCSI_OP_SCSI_TMFUNC:
+ transport_generic_free_cmd(&cmd->se_cmd, 1);
+ break;
+ default:
+ iscsit_release_cmd(cmd);
+ break;
+ }
+}
+
int iscsit_check_session_usage_count(struct iscsi_session *sess)
{
spin_lock_bh(&sess->session_usage_lock);
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 2cd49d607bda..835bf7de0281 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -30,6 +30,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
extern void iscsit_release_cmd(struct iscsi_cmd *);
+extern void iscsit_free_cmd(struct iscsi_cmd *);
extern int iscsit_check_session_usage_count(struct iscsi_session *);
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
extern void iscsit_inc_session_usage_count(struct iscsi_session *);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index aa2d67997235..3df1c9b8ae6b 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -174,6 +174,24 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
sgl_bidi = sdb->table.sgl;
sgl_bidi_count = sdb->table.nents;
}
+ /*
+ * Because some userspace code via scsi-generic do not memset their
+ * associated read buffers, go ahead and do that here for type
+ * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently
+ * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
+ * by target core in transport_generic_allocate_tasks() ->
+ * transport_generic_cmd_sequencer().
+ */
+ if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
+ se_cmd->data_direction == DMA_FROM_DEVICE) {
+ struct scatterlist *sg = scsi_sglist(sc);
+ unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
+
+ if (buf != NULL) {
+ memset(buf, 0, sg->length);
+ kunmap(sg_page(sg));
+ }
+ }
/* Tell the core about our preallocated memory */
ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
@@ -187,7 +205,7 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
/*
* Called from struct target_core_fabric_ops->check_stop_free()
*/
-static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
+static int tcm_loop_check_stop_free(struct se_cmd *se_cmd)
{
/*
* Do not release struct se_cmd's containing a valid TMR
@@ -195,12 +213,13 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
* with transport_generic_free_cmd().
*/
if (se_cmd->se_tmr_req)
- return;
+ return 0;
/*
* Release the struct se_cmd, which will make a callback to release
* struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
*/
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
+ return 1;
}
static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
@@ -290,6 +309,15 @@ static int tcm_loop_queuecommand(
*/
tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
+ /*
+ * Ensure that this tl_tpg reference from the incoming sc->device->id
+ * has already been configured via tcm_loop_make_naa_tpg().
+ */
+ if (!tl_tpg->tl_hba) {
+ set_host_byte(sc, DID_NO_CONNECT);
+ sc->scsi_done(sc);
+ return 0;
+ }
se_tpg = &tl_tpg->tl_se_tpg;
/*
* Determine the SAM Task Attribute and allocate tl_cmd and
@@ -366,7 +394,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
* Allocate the LUN_RESET TMR
*/
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr,
- TMR_LUN_RESET);
+ TMR_LUN_RESET, GFP_KERNEL);
if (IS_ERR(se_cmd->se_tmr_req))
goto release;
/*
@@ -388,7 +416,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
SUCCESS : FAILED;
release:
if (se_cmd)
- transport_generic_free_cmd(se_cmd, 1, 0);
+ transport_generic_free_cmd(se_cmd, 1);
else
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
kfree(tl_tmr);
@@ -1245,6 +1273,9 @@ void tcm_loop_drop_naa_tpg(
*/
core_tpg_deregister(se_tpg);
+ tl_tpg->tl_hba = NULL;
+ tl_tpg->tl_tpgt = 0;
+
pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s"
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
config_item_name(&wwn->wwn_group.cg_item), tpgt);
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 98c98a3a0250..88f2ad43ec8b 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -24,10 +24,10 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/configfs.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -59,8 +59,9 @@ struct t10_alua_lu_gp *default_lu_gp;
*
* See spc4r17 section 6.27
*/
-int core_emulate_report_target_port_groups(struct se_cmd *cmd)
+int target_emulate_report_target_port_groups(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
struct se_port *port;
struct t10_alua_tg_pt_gp *tg_pt_gp;
@@ -68,6 +69,15 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
unsigned char *buf;
u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
Target port group descriptor */
+ /*
+ * Need at least 4 bytes of response data or else we can't
+ * even fit the return data length.
+ */
+ if (cmd->data_length < 4) {
+ pr_warn("REPORT TARGET PORT GROUPS allocation length %u"
+ " too small\n", cmd->data_length);
+ return -EINVAL;
+ }
buf = transport_kmap_first_data_page(cmd);
@@ -75,6 +85,17 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list,
tg_pt_gp_list) {
/*
+ * Check if the Target port group and Target port descriptor list
+ * based on tg_pt_gp_members count will fit into the response payload.
+ * Otherwise, bump rd_len to let the initiator know we have exceeded
+ * the allocation length and the response is truncated.
+ */
+ if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) >
+ cmd->data_length) {
+ rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4);
+ continue;
+ }
+ /*
* PREF: Preferred target port bit, determine if this
* bit should be set for port group.
*/
@@ -145,6 +166,8 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
@@ -153,8 +176,9 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
*
* See spc4r17 section 6.35
*/
-int core_emulate_set_target_port_groups(struct se_cmd *cmd)
+int target_emulate_set_target_port_groups(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
struct se_subsystem_dev *su_dev = dev->se_sub_dev;
struct se_port *port, *l_port = cmd->se_lun->lun_sep;
@@ -322,7 +346,8 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd)
out:
transport_kunmap_first_data_page(cmd);
-
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index c86f97a081ed..c5b4ecd3e745 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -66,8 +66,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
-extern int core_emulate_report_target_port_groups(struct se_cmd *);
-extern int core_emulate_set_target_port_groups(struct se_cmd *);
+extern int target_emulate_report_target_port_groups(struct se_task *);
+extern int target_emulate_set_target_port_groups(struct se_task *);
extern int core_alua_check_nonop_delay(struct se_cmd *);
extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
struct se_device *, struct se_port *,
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index f04d4ef99dca..683ba02b8247 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -24,7 +24,7 @@
*/
#include <linux/kernel.h>
-#include <linux/ctype.h>
+#include <linux/module.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
@@ -32,6 +32,7 @@
#include <target/target_core_transport.h>
#include <target/target_core_fabric_ops.h>
#include "target_core_ua.h"
+#include "target_core_cdb.h"
static void
target_fill_alua_data(struct se_port *port, unsigned char *buf)
@@ -156,11 +157,12 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
}
static void
-target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_off)
+target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf)
{
unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
- unsigned char *buf = buf_off;
- int cnt = 0, next = 1;
+ int cnt;
+ bool next = true;
+
/*
* Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
* byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
@@ -169,19 +171,18 @@ target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_of
* NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
* per device uniqeness.
*/
- while (*p != '\0') {
- if (cnt >= 13)
- break;
- if (!isxdigit(*p)) {
- p++;
+ for (cnt = 0; *p && cnt < 13; p++) {
+ int val = hex_to_bin(*p);
+
+ if (val < 0)
continue;
- }
- if (next != 0) {
- buf[cnt++] |= hex_to_bin(*p++);
- next = 0;
+
+ if (next) {
+ next = false;
+ buf[cnt++] |= val;
} else {
- buf[cnt] = hex_to_bin(*p++) << 4;
- next = 1;
+ next = true;
+ buf[cnt] = val << 4;
}
}
}
@@ -679,16 +680,18 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
return 0;
}
-static int
-target_emulate_inquiry(struct se_cmd *cmd)
+int target_emulate_inquiry(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned char *cdb = cmd->t_task_cdb;
int p, ret;
- if (!(cdb[1] & 0x1))
- return target_emulate_inquiry_std(cmd);
+ if (!(cdb[1] & 0x1)) {
+ ret = target_emulate_inquiry_std(cmd);
+ goto out;
+ }
/*
* Make sure we at least have 4 bytes of INQUIRY response
@@ -707,22 +710,30 @@ target_emulate_inquiry(struct se_cmd *cmd)
buf[0] = dev->transport->get_device_type(dev);
- for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)
+ for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
if (cdb[2] == evpd_handlers[p].page) {
buf[1] = cdb[2];
ret = evpd_handlers[p].emulate(cmd, buf);
- transport_kunmap_first_data_page(cmd);
- return ret;
+ goto out_unmap;
}
+ }
- transport_kunmap_first_data_page(cmd);
pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]);
- return -EINVAL;
+ ret = -EINVAL;
+
+out_unmap:
+ transport_kunmap_first_data_page(cmd);
+out:
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return ret;
}
-static int
-target_emulate_readcapacity(struct se_cmd *cmd)
+int target_emulate_readcapacity(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks_long = dev->transport->get_blocks(dev);
@@ -751,12 +762,14 @@ target_emulate_readcapacity(struct se_cmd *cmd)
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
-static int
-target_emulate_readcapacity_16(struct se_cmd *cmd)
+int target_emulate_readcapacity_16(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks = dev->transport->get_blocks(dev);
@@ -784,6 +797,8 @@ target_emulate_readcapacity_16(struct se_cmd *cmd)
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
@@ -922,14 +937,15 @@ target_modesense_dpofua(unsigned char *buf, int type)
}
}
-static int
-target_emulate_modesense(struct se_cmd *cmd, int ten)
+int target_emulate_modesense(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
char *cdb = cmd->t_task_cdb;
unsigned char *rbuf;
int type = dev->transport->get_device_type(dev);
- int offset = (ten) ? 8 : 4;
+ int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
+ int offset = ten ? 8 : 4;
int length = 0;
unsigned char buf[SE_MODE_PAGE_BUF];
@@ -995,12 +1011,14 @@ target_emulate_modesense(struct se_cmd *cmd, int ten)
memcpy(rbuf, buf, offset);
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
-static int
-target_emulate_request_sense(struct se_cmd *cmd)
+int target_emulate_request_sense(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
unsigned char *cdb = cmd->t_task_cdb;
unsigned char *buf;
u8 ua_asc = 0, ua_ascq = 0;
@@ -1059,7 +1077,8 @@ target_emulate_request_sense(struct se_cmd *cmd)
end:
transport_kunmap_first_data_page(cmd);
-
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
@@ -1067,8 +1086,7 @@ end:
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
-static int
-target_emulate_unmap(struct se_task *task)
+int target_emulate_unmap(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
@@ -1079,6 +1097,12 @@ target_emulate_unmap(struct se_task *task)
int ret = 0, offset;
unsigned short dl, bd_dl;
+ if (!dev->transport->do_discard) {
+ pr_err("UNMAP emulation not supported for: %s\n",
+ dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
/* First UNMAP block descriptor starts at 8 byte offset */
offset = 8;
size -= 8;
@@ -1110,7 +1134,10 @@ target_emulate_unmap(struct se_task *task)
err:
transport_kunmap_first_data_page(cmd);
-
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
return ret;
}
@@ -1118,14 +1145,28 @@ err:
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
-static int
-target_emulate_write_same(struct se_task *task, u32 num_blocks)
+int target_emulate_write_same(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
sector_t range;
sector_t lba = cmd->t_task_lba;
+ u32 num_blocks;
int ret;
+
+ if (!dev->transport->do_discard) {
+ pr_err("WRITE_SAME emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ if (cmd->t_task_cdb[0] == WRITE_SAME)
+ num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
+ else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
+ num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
+ else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
+ num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
+
/*
* Use the explicit range when non zero is supplied, otherwise calculate
* the remaining range based on ->get_blocks() - starting LBA.
@@ -1144,125 +1185,77 @@ target_emulate_write_same(struct se_task *task, u32 num_blocks)
return ret;
}
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
-int
-transport_emulate_control_cdb(struct se_task *task)
+int target_emulate_synchronize_cache(struct se_task *task)
{
- struct se_cmd *cmd = task->task_se_cmd;
- struct se_device *dev = cmd->se_dev;
- unsigned short service_action;
- int ret = 0;
+ struct se_device *dev = task->task_se_cmd->se_dev;
- switch (cmd->t_task_cdb[0]) {
- case INQUIRY:
- ret = target_emulate_inquiry(cmd);
- break;
- case READ_CAPACITY:
- ret = target_emulate_readcapacity(cmd);
- break;
- case MODE_SENSE:
- ret = target_emulate_modesense(cmd, 0);
- break;
- case MODE_SENSE_10:
- ret = target_emulate_modesense(cmd, 1);
- break;
- case SERVICE_ACTION_IN:
- switch (cmd->t_task_cdb[1] & 0x1f) {
- case SAI_READ_CAPACITY_16:
- ret = target_emulate_readcapacity_16(cmd);
+ if (!dev->transport->do_sync_cache) {
+ pr_err("SYNCHRONIZE_CACHE emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ dev->transport->do_sync_cache(task);
+ return 0;
+}
+
+int target_emulate_noop(struct se_task *task)
+{
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ return 0;
+}
+
+/*
+ * Write a CDB into @cdb that is based on the one the intiator sent us,
+ * but updated to only cover the sectors that the current task handles.
+ */
+void target_get_task_cdb(struct se_task *task, unsigned char *cdb)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ unsigned int cdb_len = scsi_command_size(cmd->t_task_cdb);
+
+ memcpy(cdb, cmd->t_task_cdb, cdb_len);
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ unsigned long long lba = task->task_lba;
+ u32 sectors = task->task_sectors;
+
+ switch (cdb_len) {
+ case 6:
+ /* 21-bit LBA and 8-bit sectors */
+ cdb[1] = (lba >> 16) & 0x1f;
+ cdb[2] = (lba >> 8) & 0xff;
+ cdb[3] = lba & 0xff;
+ cdb[4] = sectors & 0xff;
break;
- default:
- pr_err("Unsupported SA: 0x%02x\n",
- cmd->t_task_cdb[1] & 0x1f);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- break;
- case REQUEST_SENSE:
- ret = target_emulate_request_sense(cmd);
- break;
- case UNMAP:
- if (!dev->transport->do_discard) {
- pr_err("UNMAP emulation not supported for: %s\n",
- dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_unmap(task);
- break;
- case WRITE_SAME:
- if (!dev->transport->do_discard) {
- pr_err("WRITE_SAME emulation not supported"
- " for: %s\n", dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_write_same(task,
- get_unaligned_be16(&cmd->t_task_cdb[7]));
- break;
- case WRITE_SAME_16:
- if (!dev->transport->do_discard) {
- pr_err("WRITE_SAME_16 emulation not supported"
- " for: %s\n", dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_write_same(task,
- get_unaligned_be32(&cmd->t_task_cdb[10]));
- break;
- case VARIABLE_LENGTH_CMD:
- service_action =
- get_unaligned_be16(&cmd->t_task_cdb[8]);
- switch (service_action) {
- case WRITE_SAME_32:
- if (!dev->transport->do_discard) {
- pr_err("WRITE_SAME_32 SA emulation not"
- " supported for: %s\n",
- dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_write_same(task,
- get_unaligned_be32(&cmd->t_task_cdb[28]));
+ case 10:
+ /* 32-bit LBA and 16-bit sectors */
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be16(sectors, &cdb[7]);
break;
- default:
- pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
- " 0x%02x\n", service_action);
+ case 12:
+ /* 32-bit LBA and 32-bit sectors */
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be32(sectors, &cdb[6]);
break;
+ case 16:
+ /* 64-bit LBA and 32-bit sectors */
+ put_unaligned_be64(lba, &cdb[2]);
+ put_unaligned_be32(sectors, &cdb[10]);
+ break;
+ case 32:
+ /* 64-bit LBA and 32-bit sectors, extended CDB */
+ put_unaligned_be64(lba, &cdb[12]);
+ put_unaligned_be32(sectors, &cdb[28]);
+ break;
+ default:
+ BUG();
}
- break;
- case SYNCHRONIZE_CACHE:
- case 0x91: /* SYNCHRONIZE_CACHE_16: */
- if (!dev->transport->do_sync_cache) {
- pr_err("SYNCHRONIZE_CACHE emulation not supported"
- " for: %s\n", dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- dev->transport->do_sync_cache(task);
- break;
- case ALLOW_MEDIUM_REMOVAL:
- case ERASE:
- case REZERO_UNIT:
- case SEEK_10:
- case SPACE:
- case START_STOP:
- case TEST_UNIT_READY:
- case VERIFY:
- case WRITE_FILEMARKS:
- break;
- default:
- pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n",
- cmd->t_task_cdb[0], dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
-
- if (ret < 0)
- return ret;
- /*
- * Handle the successful completion here unless a caller
- * has explictly requested an asychronous completion.
- */
- if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
-
- return PYX_TRANSPORT_SENT_TO_TRANSPORT;
}
+EXPORT_SYMBOL(target_get_task_cdb);
diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h
new file mode 100644
index 000000000000..ad6b1e393001
--- /dev/null
+++ b/drivers/target/target_core_cdb.h
@@ -0,0 +1,14 @@
+#ifndef TARGET_CORE_CDB_H
+#define TARGET_CORE_CDB_H
+
+int target_emulate_inquiry(struct se_task *task);
+int target_emulate_readcapacity(struct se_task *task);
+int target_emulate_readcapacity_16(struct se_task *task);
+int target_emulate_modesense(struct se_task *task);
+int target_emulate_request_sense(struct se_task *task);
+int target_emulate_unmap(struct se_task *task);
+int target_emulate_write_same(struct se_task *task);
+int target_emulate_synchronize_cache(struct se_task *task);
+int target_emulate_noop(struct se_task *task);
+
+#endif /* TARGET_CORE_CDB_H */
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index b2575d8568cc..e0c1e8a8dd4e 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -23,7 +23,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>
@@ -133,14 +132,6 @@ static struct config_group *target_core_register_fabric(
pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:"
" %s\n", group, name);
/*
- * Ensure that TCM subsystem plugins are loaded at this point for
- * using the RAMDISK_DR virtual LUN 0 and all other struct se_port
- * LUN symlinks.
- */
- if (transport_subsystem_check_init() < 0)
- return ERR_PTR(-EINVAL);
-
- /*
* Below are some hardcoded request_module() calls to automatically
* local fabric modules when the following is called:
*
@@ -725,9 +716,6 @@ SE_DEV_ATTR_RO(hw_queue_depth);
DEF_DEV_ATTRIB(queue_depth);
SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
-DEF_DEV_ATTRIB(task_timeout);
-SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR);
-
DEF_DEV_ATTRIB(max_unmap_lba_count);
SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
@@ -761,7 +749,6 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
&target_core_dev_attrib_optimal_sectors.attr,
&target_core_dev_attrib_hw_queue_depth.attr,
&target_core_dev_attrib_queue_depth.attr,
- &target_core_dev_attrib_task_timeout.attr,
&target_core_dev_attrib_max_unmap_lba_count.attr,
&target_core_dev_attrib_max_unmap_block_desc_count.attr,
&target_core_dev_attrib_unmap_granularity.attr,
@@ -3080,8 +3067,7 @@ static struct config_group *target_core_call_addhbatotarget(
/*
* Load up TCM subsystem plugins if they have not already been loaded.
*/
- if (transport_subsystem_check_init() < 0)
- return ERR_PTR(-EINVAL);
+ transport_subsystem_check_init();
hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0);
if (IS_ERR(hba))
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index ca6e4a4df134..ba5edec2c5f8 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/in.h>
+#include <linux/export.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
@@ -651,23 +652,15 @@ void core_dev_unexport(
lun->lun_se_dev = NULL;
}
-int transport_core_report_lun_response(struct se_cmd *se_cmd)
+int target_report_luns(struct se_task *se_task)
{
+ struct se_cmd *se_cmd = se_task->task_se_cmd;
struct se_dev_entry *deve;
struct se_lun *se_lun;
struct se_session *se_sess = se_cmd->se_sess;
- struct se_task *se_task;
unsigned char *buf;
u32 cdb_offset = 0, lun_count = 0, offset = 8, i;
- list_for_each_entry(se_task, &se_cmd->t_task_list, t_list)
- break;
-
- if (!se_task) {
- pr_err("Unable to locate struct se_task for struct se_cmd\n");
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- }
-
buf = transport_kmap_first_data_page(se_cmd);
/*
@@ -713,6 +706,8 @@ done:
buf[2] = ((lun_count >> 8) & 0xff);
buf[3] = (lun_count & 0xff);
+ se_task->task_scsi_status = GOOD;
+ transport_complete_task(se_task, 1);
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
}
@@ -914,21 +909,6 @@ void se_dev_set_default_attribs(
dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth;
}
-int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout)
-{
- if (task_timeout > DA_TASK_TIMEOUT_MAX) {
- pr_err("dev[%p]: Passed task_timeout: %u larger then"
- " DA_TASK_TIMEOUT_MAX\n", dev, task_timeout);
- return -EINVAL;
- } else {
- dev->se_sub_dev->se_dev_attrib.task_timeout = task_timeout;
- pr_debug("dev[%p]: Set SE Device task_timeout: %u\n",
- dev, task_timeout);
- }
-
- return 0;
-}
-
int se_dev_set_max_unmap_lba_count(
struct se_device *dev,
u32 max_unmap_lba_count)
@@ -972,36 +952,24 @@ int se_dev_set_unmap_granularity_alignment(
int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->dpo_emulated == NULL) {
- pr_err("dev->transport->dpo_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->dpo_emulated(dev) == 0) {
- pr_err("dev->transport->dpo_emulated not supported\n");
- return -EINVAL;
- }
- dev->se_sub_dev->se_dev_attrib.emulate_dpo = flag;
- pr_debug("dev[%p]: SE Device Page Out (DPO) Emulation"
- " bit: %d\n", dev, dev->se_sub_dev->se_dev_attrib.emulate_dpo);
- return 0;
+
+ pr_err("dpo_emulated not supported\n");
+ return -EINVAL;
}
int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->fua_write_emulated == NULL) {
- pr_err("dev->transport->fua_write_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->fua_write_emulated(dev) == 0) {
- pr_err("dev->transport->fua_write_emulated not supported\n");
+
+ if (dev->transport->fua_write_emulated == 0) {
+ pr_err("fua_write_emulated not supported\n");
return -EINVAL;
}
dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag;
@@ -1012,36 +980,23 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
int se_dev_set_emulate_fua_read(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->fua_read_emulated == NULL) {
- pr_err("dev->transport->fua_read_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->fua_read_emulated(dev) == 0) {
- pr_err("dev->transport->fua_read_emulated not supported\n");
- return -EINVAL;
- }
- dev->se_sub_dev->se_dev_attrib.emulate_fua_read = flag;
- pr_debug("dev[%p]: SE Device Forced Unit Access READs: %d\n",
- dev, dev->se_sub_dev->se_dev_attrib.emulate_fua_read);
- return 0;
+
+ pr_err("ua read emulated not supported\n");
+ return -EINVAL;
}
int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->write_cache_emulated == NULL) {
- pr_err("dev->transport->write_cache_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->write_cache_emulated(dev) == 0) {
- pr_err("dev->transport->write_cache_emulated not supported\n");
+ if (dev->transport->write_cache_emulated == 0) {
+ pr_err("write_cache_emulated not supported\n");
return -EINVAL;
}
dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 55bbe0847a6d..09b6f8729f91 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -22,7 +22,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>
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
index c4ea3a9a555b..ec4249be617e 100644
--- a/drivers/target/target_core_fabric_lib.c
+++ b/drivers/target/target_core_fabric_lib.c
@@ -29,6 +29,7 @@
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/spinlock.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -63,6 +64,7 @@ u32 sas_get_pr_transport_id(
unsigned char *buf)
{
unsigned char *ptr;
+ int ret;
/*
* Set PROTOCOL IDENTIFIER to 6h for SAS
@@ -74,7 +76,9 @@ u32 sas_get_pr_transport_id(
*/
ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */
- hex2bin(&buf[4], ptr, 8);
+ ret = hex2bin(&buf[4], ptr, 8);
+ if (ret < 0)
+ pr_debug("sas transport_id: invalid hex string\n");
/*
* The SAS Transport ID is a hardcoded 24-byte length
@@ -156,8 +160,9 @@ u32 fc_get_pr_transport_id(
unsigned char *buf)
{
unsigned char *ptr;
- int i;
+ int i, ret;
u32 off = 8;
+
/*
* PROTOCOL IDENTIFIER is 0h for FCP-2
*
@@ -174,7 +179,9 @@ u32 fc_get_pr_transport_id(
i++;
continue;
}
- hex2bin(&buf[off++], &ptr[i], 1);
+ ret = hex2bin(&buf[off++], &ptr[i], 1);
+ if (ret < 0)
+ pr_debug("fc transport_id: invalid hex string\n");
i += 2;
}
/*
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index bc1b33639b8d..67cd6fe05bfa 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -26,13 +26,13 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -273,13 +273,14 @@ fd_alloc_task(unsigned char *cdb)
static int fd_do_readv(struct se_task *task)
{
struct fd_request *req = FILE_REQ(task);
- struct fd_dev *dev = req->fd_task.se_dev->dev_ptr;
+ struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
+ struct fd_dev *dev = se_dev->dev_ptr;
struct file *fd = dev->fd_file;
struct scatterlist *sg = task->task_sg;
struct iovec *iov;
mm_segment_t old_fs;
loff_t pos = (task->task_lba *
- task->se_dev->se_sub_dev->se_dev_attrib.block_size);
+ se_dev->se_sub_dev->se_dev_attrib.block_size);
int ret = 0, i;
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
@@ -325,13 +326,14 @@ static int fd_do_readv(struct se_task *task)
static int fd_do_writev(struct se_task *task)
{
struct fd_request *req = FILE_REQ(task);
- struct fd_dev *dev = req->fd_task.se_dev->dev_ptr;
+ struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
+ struct fd_dev *dev = se_dev->dev_ptr;
struct file *fd = dev->fd_file;
struct scatterlist *sg = task->task_sg;
struct iovec *iov;
mm_segment_t old_fs;
loff_t pos = (task->task_lba *
- task->se_dev->se_sub_dev->se_dev_attrib.block_size);
+ se_dev->se_sub_dev->se_dev_attrib.block_size);
int ret, i = 0;
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
@@ -399,33 +401,6 @@ static void fd_emulate_sync_cache(struct se_task *task)
}
/*
- * Tell TCM Core that we are capable of WriteCache emulation for
- * an underlying struct se_device.
- */
-static int fd_emulated_write_cache(struct se_device *dev)
-{
- return 1;
-}
-
-static int fd_emulated_dpo(struct se_device *dev)
-{
- return 0;
-}
-/*
- * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
- * for TYPE_DISK.
- */
-static int fd_emulated_fua_write(struct se_device *dev)
-{
- return 1;
-}
-
-static int fd_emulated_fua_read(struct se_device *dev)
-{
- return 0;
-}
-
-/*
* WRITE Force Unit Access (FUA) emulation on a per struct se_task
* LBA range basis..
*/
@@ -608,17 +583,6 @@ static ssize_t fd_show_configfs_dev_params(
return bl;
}
-/* fd_get_cdb(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static unsigned char *fd_get_cdb(struct se_task *task)
-{
- struct fd_request *req = FILE_REQ(task);
-
- return req->fd_scsi_cdb;
-}
-
/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
*
*
@@ -650,15 +614,13 @@ static struct se_subsystem_api fileio_template = {
.name = "fileio",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .write_cache_emulated = 1,
+ .fua_write_emulated = 1,
.attach_hba = fd_attach_hba,
.detach_hba = fd_detach_hba,
.allocate_virtdevice = fd_allocate_virtdevice,
.create_virtdevice = fd_create_virtdevice,
.free_device = fd_free_device,
- .dpo_emulated = fd_emulated_dpo,
- .fua_write_emulated = fd_emulated_fua_write,
- .fua_read_emulated = fd_emulated_fua_read,
- .write_cache_emulated = fd_emulated_write_cache,
.alloc_task = fd_alloc_task,
.do_task = fd_do_task,
.do_sync_cache = fd_emulate_sync_cache,
@@ -666,7 +628,6 @@ static struct se_subsystem_api fileio_template = {
.check_configfs_dev_params = fd_check_configfs_dev_params,
.set_configfs_dev_params = fd_set_configfs_dev_params,
.show_configfs_dev_params = fd_show_configfs_dev_params,
- .get_cdb = fd_get_cdb,
.get_device_rev = fd_get_device_rev,
.get_device_type = fd_get_device_type,
.get_blocks = fd_get_blocks,
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
index daebd710b893..59e6e73106c2 100644
--- a/drivers/target/target_core_file.h
+++ b/drivers/target/target_core_file.h
@@ -14,9 +14,7 @@
struct fd_request {
struct se_task fd_task;
- /* SCSI CDB from iSCSI Command PDU */
- unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
-} ____cacheline_aligned;
+};
#define FBDF_HAS_PATH 0x01
#define FBDF_HAS_SIZE 0x02
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
index 0639b975d6f5..c68019d6c406 100644
--- a/drivers/target/target_core_hba.c
+++ b/drivers/target/target_core_hba.c
@@ -32,6 +32,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/in.h>
+#include <linux/module.h>
#include <net/sock.h>
#include <net/tcp.h>
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 7e1234105442..7698efe29262 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -27,7 +27,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -38,6 +37,7 @@
#include <linux/bio.h>
#include <linux/genhd.h>
#include <linux/file.h>
+#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -314,104 +314,42 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(
return blocks_long;
}
+static void iblock_end_io_flush(struct bio *bio, int err)
+{
+ struct se_cmd *cmd = bio->bi_private;
+
+ if (err)
+ pr_err("IBLOCK: cache flush failed: %d\n", err);
+
+ if (cmd)
+ transport_complete_sync_cache(cmd, err == 0);
+ bio_put(bio);
+}
+
/*
- * Emulate SYCHRONIZE_CACHE_*
+ * Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must
+ * always flush the whole cache.
*/
static void iblock_emulate_sync_cache(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
int immed = (cmd->t_task_cdb[1] & 0x2);
- sector_t error_sector;
- int ret;
+ struct bio *bio;
/*
* If the Immediate bit is set, queue up the GOOD response
- * for this SYNCHRONIZE_CACHE op
+ * for this SYNCHRONIZE_CACHE op.
*/
if (immed)
transport_complete_sync_cache(cmd, 1);
- /*
- * blkdev_issue_flush() does not support a specifying a range, so
- * we have to flush the entire cache.
- */
- ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector);
- if (ret != 0) {
- pr_err("IBLOCK: block_issue_flush() failed: %d "
- " error_sector: %llu\n", ret,
- (unsigned long long)error_sector);
- }
-
+ bio = bio_alloc(GFP_KERNEL, 0);
+ bio->bi_end_io = iblock_end_io_flush;
+ bio->bi_bdev = ib_dev->ibd_bd;
if (!immed)
- transport_complete_sync_cache(cmd, ret == 0);
-}
-
-/*
- * Tell TCM Core that we are capable of WriteCache emulation for
- * an underlying struct se_device.
- */
-static int iblock_emulated_write_cache(struct se_device *dev)
-{
- return 1;
-}
-
-static int iblock_emulated_dpo(struct se_device *dev)
-{
- return 0;
-}
-
-/*
- * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
- * for TYPE_DISK.
- */
-static int iblock_emulated_fua_write(struct se_device *dev)
-{
- return 1;
-}
-
-static int iblock_emulated_fua_read(struct se_device *dev)
-{
- return 0;
-}
-
-static int iblock_do_task(struct se_task *task)
-{
- struct se_device *dev = task->task_se_cmd->se_dev;
- struct iblock_req *req = IBLOCK_REQ(task);
- struct bio *bio = req->ib_bio, *nbio = NULL;
- struct blk_plug plug;
- int rw;
-
- if (task->task_data_direction == DMA_TO_DEVICE) {
- /*
- * Force data to disk if we pretend to not have a volatile
- * write cache, or the initiator set the Force Unit Access bit.
- */
- if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 ||
- (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
- task->task_se_cmd->t_tasks_fua))
- rw = WRITE_FUA;
- else
- rw = WRITE;
- } else {
- rw = READ;
- }
-
- blk_start_plug(&plug);
- while (bio) {
- nbio = bio->bi_next;
- bio->bi_next = NULL;
- pr_debug("Calling submit_bio() task: %p bio: %p"
- " bio->bi_sector: %llu\n", task, bio,
- (unsigned long long)bio->bi_sector);
-
- submit_bio(rw, bio);
- bio = nbio;
- }
- blk_finish_plug(&plug);
-
- return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ bio->bi_private = cmd;
+ submit_bio(WRITE_FLUSH, bio);
}
static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
@@ -425,20 +363,7 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
static void iblock_free_task(struct se_task *task)
{
- struct iblock_req *req = IBLOCK_REQ(task);
- struct bio *bio, *hbio = req->ib_bio;
- /*
- * We only release the bio(s) here if iblock_bio_done() has not called
- * bio_put() -> iblock_bio_destructor().
- */
- while (hbio != NULL) {
- bio = hbio;
- hbio = hbio->bi_next;
- bio->bi_next = NULL;
- bio_put(bio);
- }
-
- kfree(req);
+ kfree(IBLOCK_REQ(task));
}
enum {
@@ -552,25 +477,21 @@ static ssize_t iblock_show_configfs_dev_params(
static void iblock_bio_destructor(struct bio *bio)
{
struct se_task *task = bio->bi_private;
- struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
+ struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
bio_free(bio, ib_dev->ibd_bio_set);
}
-static struct bio *iblock_get_bio(
- struct se_task *task,
- struct iblock_req *ib_req,
- struct iblock_dev *ib_dev,
- int *ret,
- sector_t lba,
- u32 sg_num)
+static struct bio *
+iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num)
{
+ struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
+ struct iblock_req *ib_req = IBLOCK_REQ(task);
struct bio *bio;
bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
if (!bio) {
pr_err("Unable to allocate memory for bio\n");
- *ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
return NULL;
}
@@ -591,17 +512,33 @@ static struct bio *iblock_get_bio(
return bio;
}
-static int iblock_map_data_SG(struct se_task *task)
+static int iblock_do_task(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
- struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
- struct iblock_req *ib_req = IBLOCK_REQ(task);
- struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct bio *bio;
+ struct bio_list list;
struct scatterlist *sg;
- int ret = 0;
u32 i, sg_num = task->task_sg_nents;
sector_t block_lba;
+ struct blk_plug plug;
+ int rw;
+
+ if (task->task_data_direction == DMA_TO_DEVICE) {
+ /*
+ * Force data to disk if we pretend to not have a volatile
+ * write cache, or the initiator set the Force Unit Access bit.
+ */
+ if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 ||
+ (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
+ task->task_se_cmd->t_tasks_fua))
+ rw = WRITE_FUA;
+ else
+ rw = WRITE;
+ } else {
+ rw = READ;
+ }
+
/*
* Do starting conversion up from non 512-byte blocksize with
* struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
@@ -620,68 +557,43 @@ static int iblock_map_data_SG(struct se_task *task)
return PYX_TRANSPORT_LU_COMM_FAILURE;
}
- bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num);
+ bio = iblock_get_bio(task, block_lba, sg_num);
if (!bio)
- return ret;
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+
+ bio_list_init(&list);
+ bio_list_add(&list, bio);
- ib_req->ib_bio = bio;
- hbio = tbio = bio;
- /*
- * Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
- * from task->task_sg -> struct scatterlist memory.
- */
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
- pr_debug("task: %p bio: %p Calling bio_add_page(): page:"
- " %p len: %u offset: %u\n", task, bio, sg_page(sg),
- sg->length, sg->offset);
-again:
- ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset);
- if (ret != sg->length) {
-
- pr_debug("*** Set bio->bi_sector: %llu\n",
- (unsigned long long)bio->bi_sector);
- pr_debug("** task->task_size: %u\n",
- task->task_size);
- pr_debug("*** bio->bi_max_vecs: %u\n",
- bio->bi_max_vecs);
- pr_debug("*** bio->bi_vcnt: %u\n",
- bio->bi_vcnt);
-
- bio = iblock_get_bio(task, ib_req, ib_dev, &ret,
- block_lba, sg_num);
+ /*
+ * XXX: if the length the device accepts is shorter than the
+ * length of the S/G list entry this will cause and
+ * endless loop. Better hope no driver uses huge pages.
+ */
+ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
+ != sg->length) {
+ bio = iblock_get_bio(task, block_lba, sg_num);
if (!bio)
goto fail;
-
- tbio = tbio->bi_next = bio;
- pr_debug("-----------------> Added +1 bio: %p to"
- " list, Going to again\n", bio);
- goto again;
+ bio_list_add(&list, bio);
}
+
/* Always in 512 byte units for Linux/Block */
block_lba += sg->length >> IBLOCK_LBA_SHIFT;
sg_num--;
- pr_debug("task: %p bio-add_page() passed!, decremented"
- " sg_num to %u\n", task, sg_num);
- pr_debug("task: %p bio_add_page() passed!, increased lba"
- " to %llu\n", task, (unsigned long long)block_lba);
- pr_debug("task: %p bio_add_page() passed!, bio->bi_vcnt:"
- " %u\n", task, bio->bi_vcnt);
}
- return 0;
+ blk_start_plug(&plug);
+ while ((bio = bio_list_pop(&list)))
+ submit_bio(rw, bio);
+ blk_finish_plug(&plug);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+
fail:
- while (hbio) {
- bio = hbio;
- hbio = hbio->bi_next;
- bio->bi_next = NULL;
+ while ((bio = bio_list_pop(&list)))
bio_put(bio);
- }
- return ret;
-}
-
-static unsigned char *iblock_get_cdb(struct se_task *task)
-{
- return IBLOCK_REQ(task)->ib_scsi_cdb;
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
}
static u32 iblock_get_device_rev(struct se_device *dev)
@@ -707,6 +619,7 @@ static void iblock_bio_done(struct bio *bio, int err)
{
struct se_task *task = bio->bi_private;
struct iblock_req *ibr = IBLOCK_REQ(task);
+
/*
* Set -EIO if !BIO_UPTODATE and the passed is still err=0
*/
@@ -721,50 +634,31 @@ static void iblock_bio_done(struct bio *bio, int err)
*/
atomic_inc(&ibr->ib_bio_err_cnt);
smp_mb__after_atomic_inc();
- bio_put(bio);
- /*
- * Wait to complete the task until the last bio as completed.
- */
- if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
- return;
-
- ibr->ib_bio = NULL;
- transport_complete_task(task, 0);
- return;
}
- pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
- task, bio, task->task_lba, (unsigned long long)bio->bi_sector, err);
- /*
- * bio_put() will call iblock_bio_destructor() to release the bio back
- * to ibr->ib_bio_set.
- */
+
bio_put(bio);
- /*
- * Wait to complete the task until the last bio as completed.
- */
+
if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
return;
- /*
- * Return GOOD status for task if zero ib_bio_err_cnt exists.
- */
- ibr->ib_bio = NULL;
- transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt)));
+
+ pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
+ task, bio, task->task_lba,
+ (unsigned long long)bio->bi_sector, err);
+
+ transport_complete_task(task, !atomic_read(&ibr->ib_bio_err_cnt));
}
static struct se_subsystem_api iblock_template = {
.name = "iblock",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
- .map_data_SG = iblock_map_data_SG,
+ .write_cache_emulated = 1,
+ .fua_write_emulated = 1,
.attach_hba = iblock_attach_hba,
.detach_hba = iblock_detach_hba,
.allocate_virtdevice = iblock_allocate_virtdevice,
.create_virtdevice = iblock_create_virtdevice,
.free_device = iblock_free_device,
- .dpo_emulated = iblock_emulated_dpo,
- .fua_write_emulated = iblock_emulated_fua_write,
- .fua_read_emulated = iblock_emulated_fua_read,
- .write_cache_emulated = iblock_emulated_write_cache,
.alloc_task = iblock_alloc_task,
.do_task = iblock_do_task,
.do_discard = iblock_do_discard,
@@ -773,7 +667,6 @@ static struct se_subsystem_api iblock_template = {
.check_configfs_dev_params = iblock_check_configfs_dev_params,
.set_configfs_dev_params = iblock_set_configfs_dev_params,
.show_configfs_dev_params = iblock_show_configfs_dev_params,
- .get_cdb = iblock_get_cdb,
.get_device_rev = iblock_get_device_rev,
.get_device_type = iblock_get_device_type,
.get_blocks = iblock_get_blocks,
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index a121cd1b6575..5cf1860c10d0 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -8,10 +8,8 @@
struct iblock_req {
struct se_task ib_task;
- unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE];
atomic_t ib_bio_cnt;
atomic_t ib_bio_err_cnt;
- struct bio *ib_bio;
} ____cacheline_aligned;
#define IBDF_HAS_UDEV_PATH 0x01
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 7fd3a161f7cc..5a4ebfc3a54f 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -25,7 +25,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
@@ -117,114 +116,21 @@ static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type)
return ret;
}
-static int core_scsi2_reservation_release(struct se_cmd *cmd)
-{
- struct se_device *dev = cmd->se_dev;
- struct se_session *sess = cmd->se_sess;
- struct se_portal_group *tpg = sess->se_tpg;
-
- if (!sess || !tpg)
- return 0;
-
- spin_lock(&dev->dev_reservation_lock);
- if (!dev->dev_reserved_node_acl || !sess) {
- spin_unlock(&dev->dev_reservation_lock);
- return 0;
- }
-
- if (dev->dev_reserved_node_acl != sess->se_node_acl) {
- spin_unlock(&dev->dev_reservation_lock);
- return 0;
- }
- dev->dev_reserved_node_acl = NULL;
- dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
- if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) {
- dev->dev_res_bin_isid = 0;
- dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID;
- }
- pr_debug("SCSI-2 Released reservation for %s LUN: %u ->"
- " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
- cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun,
- sess->se_node_acl->initiatorname);
- spin_unlock(&dev->dev_reservation_lock);
-
- return 0;
-}
-
-static int core_scsi2_reservation_reserve(struct se_cmd *cmd)
-{
- struct se_device *dev = cmd->se_dev;
- struct se_session *sess = cmd->se_sess;
- struct se_portal_group *tpg = sess->se_tpg;
-
- if ((cmd->t_task_cdb[1] & 0x01) &&
- (cmd->t_task_cdb[1] & 0x02)) {
- pr_err("LongIO and Obselete Bits set, returning"
- " ILLEGAL_REQUEST\n");
- return PYX_TRANSPORT_ILLEGAL_REQUEST;
- }
- /*
- * This is currently the case for target_core_mod passthrough struct se_cmd
- * ops
- */
- if (!sess || !tpg)
- return 0;
-
- spin_lock(&dev->dev_reservation_lock);
- if (dev->dev_reserved_node_acl &&
- (dev->dev_reserved_node_acl != sess->se_node_acl)) {
- pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n",
- tpg->se_tpg_tfo->get_fabric_name());
- pr_err("Original reserver LUN: %u %s\n",
- cmd->se_lun->unpacked_lun,
- dev->dev_reserved_node_acl->initiatorname);
- pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u"
- " from %s \n", cmd->se_lun->unpacked_lun,
- cmd->se_deve->mapped_lun,
- sess->se_node_acl->initiatorname);
- spin_unlock(&dev->dev_reservation_lock);
- return PYX_TRANSPORT_RESERVATION_CONFLICT;
- }
-
- dev->dev_reserved_node_acl = sess->se_node_acl;
- dev->dev_flags |= DF_SPC2_RESERVATIONS;
- if (sess->sess_bin_isid != 0) {
- dev->dev_res_bin_isid = sess->sess_bin_isid;
- dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID;
- }
- pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u"
- " for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
- cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun,
- sess->se_node_acl->initiatorname);
- spin_unlock(&dev->dev_reservation_lock);
-
- return 0;
-}
-
static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *,
struct se_node_acl *, struct se_session *);
static void core_scsi3_put_pr_reg(struct t10_pr_registration *);
-/*
- * Setup in target_core_transport.c:transport_generic_cmd_sequencer()
- * and called via struct se_cmd->transport_emulate_cdb() in TCM processing
- * thread context.
- */
-int core_scsi2_emulate_crh(struct se_cmd *cmd)
+static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
{
struct se_session *se_sess = cmd->se_sess;
struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
struct t10_pr_registration *pr_reg;
struct t10_reservation *pr_tmpl = &su_dev->t10_pr;
- unsigned char *cdb = &cmd->t_task_cdb[0];
int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS);
int conflict = 0;
- if (!se_sess)
- return 0;
-
if (!crh)
- goto after_crh;
+ return false;
pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
se_sess);
@@ -252,14 +158,16 @@ int core_scsi2_emulate_crh(struct se_cmd *cmd)
*/
if (pr_reg->pr_res_holder) {
core_scsi3_put_pr_reg(pr_reg);
- return 0;
+ *ret = 0;
+ return false;
}
if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
(pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
(pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
(pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
core_scsi3_put_pr_reg(pr_reg);
- return 0;
+ *ret = 0;
+ return true;
}
core_scsi3_put_pr_reg(pr_reg);
conflict = 1;
@@ -283,18 +191,118 @@ int core_scsi2_emulate_crh(struct se_cmd *cmd)
pr_err("Received legacy SPC-2 RESERVE/RELEASE"
" while active SPC-3 registrations exist,"
" returning RESERVATION_CONFLICT\n");
- return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ *ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ return true;
}
-after_crh:
- if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10))
- return core_scsi2_reservation_reserve(cmd);
- else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10))
- return core_scsi2_reservation_release(cmd);
- else
- return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ return false;
+}
+
+int target_scsi2_reservation_release(struct se_task *task)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ struct se_portal_group *tpg = sess->se_tpg;
+ int ret = 0;
+
+ if (!sess || !tpg)
+ goto out;
+ if (target_check_scsi2_reservation_conflict(cmd, &ret))
+ goto out;
+
+ ret = 0;
+ spin_lock(&dev->dev_reservation_lock);
+ if (!dev->dev_reserved_node_acl || !sess)
+ goto out_unlock;
+
+ if (dev->dev_reserved_node_acl != sess->se_node_acl)
+ goto out_unlock;
+
+ dev->dev_reserved_node_acl = NULL;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) {
+ dev->dev_res_bin_isid = 0;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID;
+ }
+ pr_debug("SCSI-2 Released reservation for %s LUN: %u ->"
+ " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
+ cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+
+out_unlock:
+ spin_unlock(&dev->dev_reservation_lock);
+out:
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return ret;
+}
+
+int target_scsi2_reservation_reserve(struct se_task *task)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ struct se_portal_group *tpg = sess->se_tpg;
+ int ret = 0;
+
+ if ((cmd->t_task_cdb[1] & 0x01) &&
+ (cmd->t_task_cdb[1] & 0x02)) {
+ pr_err("LongIO and Obselete Bits set, returning"
+ " ILLEGAL_REQUEST\n");
+ ret = PYX_TRANSPORT_ILLEGAL_REQUEST;
+ goto out;
+ }
+ /*
+ * This is currently the case for target_core_mod passthrough struct se_cmd
+ * ops
+ */
+ if (!sess || !tpg)
+ goto out;
+ if (target_check_scsi2_reservation_conflict(cmd, &ret))
+ goto out;
+
+ ret = 0;
+ spin_lock(&dev->dev_reservation_lock);
+ if (dev->dev_reserved_node_acl &&
+ (dev->dev_reserved_node_acl != sess->se_node_acl)) {
+ pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n",
+ tpg->se_tpg_tfo->get_fabric_name());
+ pr_err("Original reserver LUN: %u %s\n",
+ cmd->se_lun->unpacked_lun,
+ dev->dev_reserved_node_acl->initiatorname);
+ pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u"
+ " from %s \n", cmd->se_lun->unpacked_lun,
+ cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ goto out_unlock;
+ }
+
+ dev->dev_reserved_node_acl = sess->se_node_acl;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS;
+ if (sess->sess_bin_isid != 0) {
+ dev->dev_res_bin_isid = sess->sess_bin_isid;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID;
+ }
+ pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u"
+ " for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
+ cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+
+out_unlock:
+ spin_unlock(&dev->dev_reservation_lock);
+out:
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return ret;
}
+
/*
* Begin SPC-3/SPC-4 Persistent Reservations emulation support
*
@@ -419,12 +427,12 @@ static int core_scsi3_pr_seq_non_holder(
break;
case RELEASE:
case RELEASE_10:
- /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+ /* Handled by CRH=1 in target_scsi2_reservation_release() */
ret = 0;
break;
case RESERVE:
case RESERVE_10:
- /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+ /* Handled by CRH=1 in target_scsi2_reservation_reserve() */
ret = 0;
break;
case TEST_UNIT_READY:
@@ -3740,12 +3748,33 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
/*
* See spc4r17 section 6.14 Table 170
*/
-static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
+int target_scsi3_emulate_pr_out(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
+ unsigned char *cdb = &cmd->t_task_cdb[0];
unsigned char *buf;
u64 res_key, sa_res_key;
int sa, scope, type, aptpl;
int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
+ int ret;
+
+ /*
+ * Following spc2r20 5.5.1 Reservations overview:
+ *
+ * If a logical unit has been reserved by any RESERVE command and is
+ * still reserved by any initiator, all PERSISTENT RESERVE IN and all
+ * PERSISTENT RESERVE OUT commands shall conflict regardless of
+ * initiator or service action and shall terminate with a RESERVATION
+ * CONFLICT status.
+ */
+ if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) {
+ pr_err("Received PERSISTENT_RESERVE CDB while legacy"
+ " SPC-2 reservation is held, returning"
+ " RESERVATION_CONFLICT\n");
+ ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ goto out;
+ }
+
/*
* FIXME: A NULL struct se_session pointer means an this is not coming from
* a $FABRIC_MOD's nexus, but from internal passthrough ops.
@@ -3756,7 +3785,8 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
if (cmd->data_length < 24) {
pr_warn("SPC-PR: Received PR OUT parameter list"
" length too small: %u\n", cmd->data_length);
- return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
}
/*
* From the PERSISTENT_RESERVE_OUT command descriptor block (CDB)
@@ -3789,8 +3819,11 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
/*
* SPEC_I_PT=1 is only valid for Service action: REGISTER
*/
- if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER))
- return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) {
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
/*
* From spc4r17 section 6.14:
*
@@ -3804,7 +3837,8 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
(cmd->data_length != 24)) {
pr_warn("SPC-PR: Received PR OUT illegal parameter"
" list length: %u\n", cmd->data_length);
- return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
}
/*
* (core_scsi3_emulate_pro_* function parameters
@@ -3813,35 +3847,47 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
*/
switch (sa) {
case PRO_REGISTER:
- return core_scsi3_emulate_pro_register(cmd,
+ ret = core_scsi3_emulate_pro_register(cmd,
res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0);
+ break;
case PRO_RESERVE:
- return core_scsi3_emulate_pro_reserve(cmd,
- type, scope, res_key);
+ ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key);
+ break;
case PRO_RELEASE:
- return core_scsi3_emulate_pro_release(cmd,
- type, scope, res_key);
+ ret = core_scsi3_emulate_pro_release(cmd, type, scope, res_key);
+ break;
case PRO_CLEAR:
- return core_scsi3_emulate_pro_clear(cmd, res_key);
+ ret = core_scsi3_emulate_pro_clear(cmd, res_key);
+ break;
case PRO_PREEMPT:
- return core_scsi3_emulate_pro_preempt(cmd, type, scope,
+ ret = core_scsi3_emulate_pro_preempt(cmd, type, scope,
res_key, sa_res_key, 0);
+ break;
case PRO_PREEMPT_AND_ABORT:
- return core_scsi3_emulate_pro_preempt(cmd, type, scope,
+ ret = core_scsi3_emulate_pro_preempt(cmd, type, scope,
res_key, sa_res_key, 1);
+ break;
case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
- return core_scsi3_emulate_pro_register(cmd,
+ ret = core_scsi3_emulate_pro_register(cmd,
0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1);
+ break;
case PRO_REGISTER_AND_MOVE:
- return core_scsi3_emulate_pro_register_and_move(cmd, res_key,
+ ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key,
sa_res_key, aptpl, unreg);
+ break;
default:
pr_err("Unknown PERSISTENT_RESERVE_OUT service"
" action: 0x%02x\n", cdb[1] & 0x1f);
- return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ ret = PYX_TRANSPORT_INVALID_CDB_FIELD;
+ break;
}
- return PYX_TRANSPORT_INVALID_CDB_FIELD;
+out:
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return ret;
}
/*
@@ -4191,29 +4237,11 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
return 0;
}
-static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb)
+int target_scsi3_emulate_pr_in(struct se_task *task)
{
- switch (cdb[1] & 0x1f) {
- case PRI_READ_KEYS:
- return core_scsi3_pri_read_keys(cmd);
- case PRI_READ_RESERVATION:
- return core_scsi3_pri_read_reservation(cmd);
- case PRI_REPORT_CAPABILITIES:
- return core_scsi3_pri_report_capabilities(cmd);
- case PRI_READ_FULL_STATUS:
- return core_scsi3_pri_read_full_status(cmd);
- default:
- pr_err("Unknown PERSISTENT_RESERVE_IN service"
- " action: 0x%02x\n", cdb[1] & 0x1f);
- return PYX_TRANSPORT_INVALID_CDB_FIELD;
- }
-
-}
+ struct se_cmd *cmd = task->task_se_cmd;
+ int ret;
-int core_scsi3_emulate_pr(struct se_cmd *cmd)
-{
- unsigned char *cdb = &cmd->t_task_cdb[0];
- struct se_device *dev = cmd->se_dev;
/*
* Following spc2r20 5.5.1 Reservations overview:
*
@@ -4223,16 +4251,38 @@ int core_scsi3_emulate_pr(struct se_cmd *cmd)
* initiator or service action and shall terminate with a RESERVATION
* CONFLICT status.
*/
- if (dev->dev_flags & DF_SPC2_RESERVATIONS) {
+ if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) {
pr_err("Received PERSISTENT_RESERVE CDB while legacy"
" SPC-2 reservation is held, returning"
" RESERVATION_CONFLICT\n");
return PYX_TRANSPORT_RESERVATION_CONFLICT;
}
- return (cdb[0] == PERSISTENT_RESERVE_OUT) ?
- core_scsi3_emulate_pr_out(cmd, cdb) :
- core_scsi3_emulate_pr_in(cmd, cdb);
+ switch (cmd->t_task_cdb[1] & 0x1f) {
+ case PRI_READ_KEYS:
+ ret = core_scsi3_pri_read_keys(cmd);
+ break;
+ case PRI_READ_RESERVATION:
+ ret = core_scsi3_pri_read_reservation(cmd);
+ break;
+ case PRI_REPORT_CAPABILITIES:
+ ret = core_scsi3_pri_report_capabilities(cmd);
+ break;
+ case PRI_READ_FULL_STATUS:
+ ret = core_scsi3_pri_read_full_status(cmd);
+ break;
+ default:
+ pr_err("Unknown PERSISTENT_RESERVE_IN service"
+ " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f);
+ ret = PYX_TRANSPORT_INVALID_CDB_FIELD;
+ break;
+ }
+
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return ret;
}
static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type)
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index c8f47d064584..b97f6940dd05 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -47,7 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache;
extern int core_pr_dump_initiator_port(struct t10_pr_registration *,
char *, u32);
-extern int core_scsi2_emulate_crh(struct se_cmd *);
+extern int target_scsi2_reservation_release(struct se_task *task);
+extern int target_scsi2_reservation_reserve(struct se_task *task);
extern int core_scsi3_alloc_aptpl_registration(
struct t10_reservation *, u64,
unsigned char *, unsigned char *, u32,
@@ -61,7 +62,9 @@ extern void core_scsi3_free_all_registrations(struct se_device *);
extern unsigned char *core_scsi3_pr_dump_type(int);
extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *,
struct se_cmd *);
-extern int core_scsi3_emulate_pr(struct se_cmd *);
+
+extern int target_scsi3_emulate_pr_in(struct se_task *task);
+extern int target_scsi3_emulate_pr_out(struct se_task *task);
extern int core_setup_reservations(struct se_device *, int);
#endif /* TARGET_CORE_PR_H */
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 2b7b0da9146d..ed32e1efe429 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -26,7 +26,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -37,6 +36,7 @@
#include <linux/genhd.h>
#include <linux/cdrom.h>
#include <linux/file.h>
+#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
@@ -567,7 +567,7 @@ static struct se_device *pscsi_create_virtdevice(
if (IS_ERR(sh)) {
pr_err("pSCSI: Unable to locate"
" pdv_host_id: %d\n", pdv->pdv_host_id);
- return (struct se_device *) sh;
+ return ERR_CAST(sh);
}
}
} else {
@@ -677,7 +677,7 @@ static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task)
*/
static int pscsi_transport_complete(struct se_task *task)
{
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
struct scsi_device *sd = pdv->pdv_sd;
int result;
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
@@ -777,95 +777,6 @@ pscsi_alloc_task(unsigned char *cdb)
return &pt->pscsi_task;
}
-static inline void pscsi_blk_init_request(
- struct se_task *task,
- struct pscsi_plugin_task *pt,
- struct request *req,
- int bidi_read)
-{
- /*
- * Defined as "scsi command" in include/linux/blkdev.h.
- */
- req->cmd_type = REQ_TYPE_BLOCK_PC;
- /*
- * For the extra BIDI-COMMAND READ struct request we do not
- * need to setup the remaining structure members
- */
- if (bidi_read)
- return;
- /*
- * Setup the done function pointer for struct request,
- * also set the end_io_data pointer.to struct se_task.
- */
- req->end_io = pscsi_req_done;
- req->end_io_data = task;
- /*
- * Load the referenced struct se_task's SCSI CDB into
- * include/linux/blkdev.h:struct request->cmd
- */
- req->cmd_len = scsi_command_size(pt->pscsi_cdb);
- req->cmd = &pt->pscsi_cdb[0];
- /*
- * Setup pointer for outgoing sense data.
- */
- req->sense = &pt->pscsi_sense[0];
- req->sense_len = 0;
-}
-
-/*
- * Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB
-*/
-static int pscsi_blk_get_request(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
-
- pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue,
- (task->task_data_direction == DMA_TO_DEVICE),
- GFP_KERNEL);
- if (!pt->pscsi_req || IS_ERR(pt->pscsi_req)) {
- pr_err("PSCSI: blk_get_request() failed: %ld\n",
- IS_ERR(pt->pscsi_req));
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- }
- /*
- * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
- * and setup rq callback, CDB and sense.
- */
- pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
- return 0;
-}
-
-/* pscsi_do_task(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static int pscsi_do_task(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
- /*
- * Set the struct request->timeout value based on peripheral
- * device type from SCSI.
- */
- if (pdv->pdv_sd->type == TYPE_DISK)
- pt->pscsi_req->timeout = PS_TIMEOUT_DISK;
- else
- pt->pscsi_req->timeout = PS_TIMEOUT_OTHER;
-
- pt->pscsi_req->retries = PS_RETRY;
- /*
- * Queue the struct request into the struct scsi_device->request_queue.
- * Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd
- * descriptor
- */
- blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req,
- (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
- pscsi_req_done);
-
- return PYX_TRANSPORT_SENT_TO_TRANSPORT;
-}
-
static void pscsi_free_task(struct se_task *task)
{
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
@@ -1049,15 +960,12 @@ static inline struct bio *pscsi_get_bio(int sg_num)
return bio;
}
-static int __pscsi_map_SG(
- struct se_task *task,
- struct scatterlist *task_sg,
- u32 task_sg_num,
- int bidi_read)
+static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg,
+ struct bio **hbio)
{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
- struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
+ u32 task_sg_num = task->task_sg_nents;
+ struct bio *bio = NULL, *tbio = NULL;
struct page *page;
struct scatterlist *sg;
u32 data_len = task->task_size, i, len, bytes, off;
@@ -1066,19 +974,8 @@ static int __pscsi_map_SG(
int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
int rw = (task->task_data_direction == DMA_TO_DEVICE);
- if (!task->task_size)
- return 0;
- /*
- * For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
- * the bio_vec maplist from task->task_sg ->
- * struct scatterlist memory. The struct se_task->task_sg[] currently needs
- * to be attached to struct bios for submission to Linux/SCSI using
- * struct request to struct scsi_device->request_queue.
- *
- * Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI
- * is ported to upstream SCSI passthrough functionality that accepts
- * struct scatterlist->page_link or struct page as a paraemeter.
- */
+ *hbio = NULL;
+
pr_debug("PSCSI: nr_pages: %d\n", nr_pages);
for_each_sg(task_sg, sg, task_sg_num, i) {
@@ -1115,8 +1012,8 @@ static int __pscsi_map_SG(
* bios need to be added to complete a given
* struct se_task
*/
- if (!hbio)
- hbio = tbio = bio;
+ if (!*hbio)
+ *hbio = tbio = bio;
else
tbio = tbio->bi_next = bio;
}
@@ -1152,92 +1049,82 @@ static int __pscsi_map_SG(
off = 0;
}
}
- /*
- * Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND
- * primary SCSI WRITE poayload mapped for struct se_task->task_sg[]
- */
- if (!bidi_read) {
- /*
- * Starting with v2.6.31, call blk_make_request() passing in *hbio to
- * allocate the pSCSI task a struct request.
- */
- pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue,
- hbio, GFP_KERNEL);
- if (!pt->pscsi_req) {
- pr_err("pSCSI: blk_make_request() failed\n");
- goto fail;
- }
- /*
- * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
- * and setup rq callback, CDB and sense.
- */
- pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
-
- return task->task_sg_nents;
- }
- /*
- * Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND
- * SCSI READ paylaod mapped for struct se_task->task_sg_bidi[]
- */
- pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue,
- hbio, GFP_KERNEL);
- if (!pt->pscsi_req->next_rq) {
- pr_err("pSCSI: blk_make_request() failed for BIDI\n");
- goto fail;
- }
- pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1);
return task->task_sg_nents;
fail:
- while (hbio) {
- bio = hbio;
- hbio = hbio->bi_next;
+ while (*hbio) {
+ bio = *hbio;
+ *hbio = (*hbio)->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, 0);
+ bio_endio(bio, 0); /* XXX: should be error */
}
return ret;
}
-/*
- * pSCSI maps both ->map_control_SG() and ->map_data_SG() to a single call.
- */
-static int pscsi_map_SG(struct se_task *task)
+static int pscsi_do_task(struct se_task *task)
{
+ struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct request *req;
+ struct bio *hbio;
int ret;
- /*
- * Setup the main struct request for the task->task_sg[] payload
- */
+ target_get_task_cdb(task, pt->pscsi_cdb);
+
+ if (task->task_se_cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+ req = blk_get_request(pdv->pdv_sd->request_queue,
+ (task->task_data_direction == DMA_TO_DEVICE),
+ GFP_KERNEL);
+ if (!req || IS_ERR(req)) {
+ pr_err("PSCSI: blk_get_request() failed: %ld\n",
+ req ? IS_ERR(req) : -ENOMEM);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ } else {
+ BUG_ON(!task->task_size);
- ret = __pscsi_map_SG(task, task->task_sg, task->task_sg_nents, 0);
- if (ret >= 0 && task->task_sg_bidi) {
/*
- * If present, set up the extra BIDI-COMMAND SCSI READ
- * struct request and payload.
+ * Setup the main struct request for the task->task_sg[] payload
*/
- ret = __pscsi_map_SG(task, task->task_sg_bidi,
- task->task_sg_nents, 1);
+ ret = pscsi_map_sg(task, task->task_sg, &hbio);
+ if (ret < 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ req = blk_make_request(pdv->pdv_sd->request_queue, hbio,
+ GFP_KERNEL);
+ if (IS_ERR(req)) {
+ pr_err("pSCSI: blk_make_request() failed\n");
+ goto fail;
+ }
}
- if (ret < 0)
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- return 0;
-}
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->end_io = pscsi_req_done;
+ req->end_io_data = task;
+ req->cmd_len = scsi_command_size(pt->pscsi_cdb);
+ req->cmd = &pt->pscsi_cdb[0];
+ req->sense = &pt->pscsi_sense[0];
+ req->sense_len = 0;
+ if (pdv->pdv_sd->type == TYPE_DISK)
+ req->timeout = PS_TIMEOUT_DISK;
+ else
+ req->timeout = PS_TIMEOUT_OTHER;
+ req->retries = PS_RETRY;
-static int pscsi_CDB_none(struct se_task *task)
-{
- return pscsi_blk_get_request(task);
-}
+ blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
+ (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
+ pscsi_req_done);
-/* pscsi_get_cdb():
- *
- *
- */
-static unsigned char *pscsi_get_cdb(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
- return pt->pscsi_cdb;
+fail:
+ while (hbio) {
+ struct bio *bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_endio(bio, 0); /* XXX: should be error */
+ }
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
}
/* pscsi_get_sense_buffer():
@@ -1328,23 +1215,13 @@ static void pscsi_req_done(struct request *req, int uptodate)
pt->pscsi_resid = req->resid_len;
pscsi_process_SAM_status(task, pt);
- /*
- * Release BIDI-READ if present
- */
- if (req->next_rq != NULL)
- __blk_put_request(req->q, req->next_rq);
-
__blk_put_request(req->q, req);
- pt->pscsi_req = NULL;
}
static struct se_subsystem_api pscsi_template = {
.name = "pscsi",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
- .cdb_none = pscsi_CDB_none,
- .map_control_SG = pscsi_map_SG,
- .map_data_SG = pscsi_map_SG,
.attach_hba = pscsi_attach_hba,
.detach_hba = pscsi_detach_hba,
.pmode_enable_hba = pscsi_pmode_enable_hba,
@@ -1358,7 +1235,6 @@ static struct se_subsystem_api pscsi_template = {
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
- .get_cdb = pscsi_get_cdb,
.get_sense_buffer = pscsi_get_sense_buffer,
.get_device_rev = pscsi_get_device_rev,
.get_device_type = pscsi_get_device_type,
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
index ebf4f1ae2c83..fdc17b6aefb3 100644
--- a/drivers/target/target_core_pscsi.h
+++ b/drivers/target/target_core_pscsi.h
@@ -27,7 +27,6 @@ struct pscsi_plugin_task {
int pscsi_direction;
int pscsi_result;
u32 pscsi_resid;
- struct request *pscsi_req;
unsigned char pscsi_cdb[0];
} ____cacheline_aligned;
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index e567e129c697..5158d3846f19 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -27,7 +27,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -351,7 +350,7 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
static int rd_MEMCPY_read(struct rd_request *req)
{
struct se_task *task = &req->rd_task;
- struct rd_dev *dev = req->rd_task.se_dev->dev_ptr;
+ struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
struct rd_dev_sg_table *table;
struct scatterlist *sg_d, *sg_s;
void *dst, *src;
@@ -467,7 +466,7 @@ static int rd_MEMCPY_read(struct rd_request *req)
static int rd_MEMCPY_write(struct rd_request *req)
{
struct se_task *task = &req->rd_task;
- struct rd_dev *dev = req->rd_task.se_dev->dev_ptr;
+ struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
struct rd_dev_sg_table *table;
struct scatterlist *sg_d, *sg_s;
void *dst, *src;
@@ -582,7 +581,7 @@ static int rd_MEMCPY_write(struct rd_request *req)
*/
static int rd_MEMCPY_do_task(struct se_task *task)
{
- struct se_device *dev = task->se_dev;
+ struct se_device *dev = task->task_se_cmd->se_dev;
struct rd_request *req = RD_REQ(task);
unsigned long long lba;
int ret;
@@ -692,17 +691,6 @@ static ssize_t rd_show_configfs_dev_params(
return bl;
}
-/* rd_get_cdb(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static unsigned char *rd_get_cdb(struct se_task *task)
-{
- struct rd_request *req = RD_REQ(task);
-
- return req->rd_scsi_cdb;
-}
-
static u32 rd_get_device_rev(struct se_device *dev)
{
return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
@@ -736,7 +724,6 @@ static struct se_subsystem_api rd_mcp_template = {
.check_configfs_dev_params = rd_check_configfs_dev_params,
.set_configfs_dev_params = rd_set_configfs_dev_params,
.show_configfs_dev_params = rd_show_configfs_dev_params,
- .get_cdb = rd_get_cdb,
.get_device_rev = rd_get_device_rev,
.get_device_type = rd_get_device_type,
.get_blocks = rd_get_blocks,
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
index 0d027732cd00..784e56a04100 100644
--- a/drivers/target/target_core_rd.h
+++ b/drivers/target/target_core_rd.h
@@ -22,8 +22,6 @@ void rd_module_exit(void);
struct rd_request {
struct se_task rd_task;
- /* SCSI CDB from iSCSI Command PDU */
- unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
/* Offset from start of page */
u32 rd_offset;
/* Starting page in Ramdisk for request */
diff --git a/drivers/target/target_core_scdb.c b/drivers/target/target_core_scdb.c
deleted file mode 100644
index 72843441d4fa..000000000000
--- a/drivers/target/target_core_scdb.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * Filename: target_core_scdb.c
- *
- * This file contains the generic target engine Split CDB related functions.
- *
- * Copyright (c) 2004-2005 PyX Technologies, Inc.
- * Copyright (c) 2005, 2006, 2007 SBE, Inc.
- * Copyright (c) 2007-2010 Rising Tide Systems
- * Copyright (c) 2008-2010 Linux-iSCSI.org
- *
- * Nicholas A. Bellinger <nab@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- ******************************************************************************/
-
-#include <linux/net.h>
-#include <linux/string.h>
-#include <scsi/scsi.h>
-#include <asm/unaligned.h>
-
-#include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-
-#include "target_core_scdb.h"
-
-/* split_cdb_XX_6():
- *
- * 21-bit LBA w/ 8-bit SECTORS
- */
-void split_cdb_XX_6(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- cdb[1] = (lba >> 16) & 0x1f;
- cdb[2] = (lba >> 8) & 0xff;
- cdb[3] = lba & 0xff;
- cdb[4] = sectors & 0xff;
-}
-
-/* split_cdb_XX_10():
- *
- * 32-bit LBA w/ 16-bit SECTORS
- */
-void split_cdb_XX_10(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be32(lba, &cdb[2]);
- put_unaligned_be16(sectors, &cdb[7]);
-}
-
-/* split_cdb_XX_12():
- *
- * 32-bit LBA w/ 32-bit SECTORS
- */
-void split_cdb_XX_12(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be32(lba, &cdb[2]);
- put_unaligned_be32(sectors, &cdb[6]);
-}
-
-/* split_cdb_XX_16():
- *
- * 64-bit LBA w/ 32-bit SECTORS
- */
-void split_cdb_XX_16(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be64(lba, &cdb[2]);
- put_unaligned_be32(sectors, &cdb[10]);
-}
-
-/*
- * split_cdb_XX_32():
- *
- * 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32
- */
-void split_cdb_XX_32(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be64(lba, &cdb[12]);
- put_unaligned_be32(sectors, &cdb[28]);
-}
diff --git a/drivers/target/target_core_scdb.h b/drivers/target/target_core_scdb.h
deleted file mode 100644
index 48e9ccc9585e..000000000000
--- a/drivers/target/target_core_scdb.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef TARGET_CORE_SCDB_H
-#define TARGET_CORE_SCDB_H
-
-extern void split_cdb_XX_6(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_10(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_12(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_16(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_32(unsigned long long, u32, unsigned char *);
-
-#endif /* TARGET_CORE_SCDB_H */
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index a8d6e1dee938..874152aed94a 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/string.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/proc_fs.h>
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 27d4925e51c3..217e29df6297 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -24,10 +24,10 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -44,12 +44,12 @@
struct se_tmr_req *core_tmr_alloc_req(
struct se_cmd *se_cmd,
void *fabric_tmr_ptr,
- u8 function)
+ u8 function,
+ gfp_t gfp_flags)
{
struct se_tmr_req *tmr;
- tmr = kmem_cache_zalloc(se_tmr_req_cache, (in_interrupt()) ?
- GFP_ATOMIC : GFP_KERNEL);
+ tmr = kmem_cache_zalloc(se_tmr_req_cache, gfp_flags);
if (!tmr) {
pr_err("Unable to allocate struct se_tmr_req\n");
return ERR_PTR(-ENOMEM);
@@ -67,15 +67,16 @@ void core_tmr_release_req(
struct se_tmr_req *tmr)
{
struct se_device *dev = tmr->tmr_dev;
+ unsigned long flags;
if (!dev) {
kmem_cache_free(se_tmr_req_cache, tmr);
return;
}
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_del(&tmr->tmr_list);
- spin_unlock_irq(&dev->se_tmr_lock);
+ spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
kmem_cache_free(se_tmr_req_cache, tmr);
}
@@ -100,59 +101,25 @@ static void core_tmr_handle_tas_abort(
transport_cmd_finish_abort(cmd, 0);
}
-int core_tmr_lun_reset(
+static void core_tmr_drain_tmr_list(
struct se_device *dev,
struct se_tmr_req *tmr,
- struct list_head *preempt_and_abort_list,
- struct se_cmd *prout_cmd)
+ struct list_head *preempt_and_abort_list)
{
- struct se_cmd *cmd, *tcmd;
- struct se_node_acl *tmr_nacl = NULL;
- struct se_portal_group *tmr_tpg = NULL;
- struct se_queue_obj *qobj = &dev->dev_queue_obj;
+ LIST_HEAD(drain_tmr_list);
struct se_tmr_req *tmr_p, *tmr_pp;
- struct se_task *task, *task_tmp;
+ struct se_cmd *cmd;
unsigned long flags;
- int fe_count, tas;
- /*
- * TASK_ABORTED status bit, this is configurable via ConfigFS
- * struct se_device attributes. spc4r17 section 7.4.6 Control mode page
- *
- * A task aborted status (TAS) bit set to zero specifies that aborted
- * tasks shall be terminated by the device server without any response
- * to the application client. A TAS bit set to one specifies that tasks
- * aborted by the actions of an I_T nexus other than the I_T nexus on
- * which the command was received shall be completed with TASK ABORTED
- * status (see SAM-4).
- */
- tas = dev->se_sub_dev->se_dev_attrib.emulate_tas;
- /*
- * Determine if this se_tmr is coming from a $FABRIC_MOD
- * or struct se_device passthrough..
- */
- if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
- tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
- tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
- if (tmr_nacl && tmr_tpg) {
- pr_debug("LUN_RESET: TMR caller fabric: %s"
- " initiator port %s\n",
- tmr_tpg->se_tpg_tfo->get_fabric_name(),
- tmr_nacl->initiatorname);
- }
- }
- pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n",
- (preempt_and_abort_list) ? "Preempt" : "TMR",
- dev->transport->name, tas);
/*
* Release all pending and outgoing TMRs aside from the received
* LUN_RESET tmr..
*/
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) {
/*
* Allow the received TMR to return with FUNCTION_COMPLETE.
*/
- if (tmr && (tmr_p == tmr))
+ if (tmr_p == tmr)
continue;
cmd = tmr_p->task_cmd;
@@ -169,29 +136,47 @@ int core_tmr_lun_reset(
(core_scsi3_check_cdb_abort_and_preempt(
preempt_and_abort_list, cmd) != 0))
continue;
- spin_unlock_irq(&dev->se_tmr_lock);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
+ spin_lock(&cmd->t_state_lock);
if (!atomic_read(&cmd->t_transport_active)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_unlock(&cmd->t_state_lock);
continue;
}
if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_unlock(&cmd->t_state_lock);
continue;
}
+ spin_unlock(&cmd->t_state_lock);
+
+ list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
+ }
+ spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+
+ list_for_each_entry_safe(tmr_p, tmr_pp, &drain_tmr_list, tmr_list) {
+ list_del_init(&tmr_p->tmr_list);
+ cmd = tmr_p->task_cmd;
+
pr_debug("LUN_RESET: %s releasing TMR %p Function: 0x%02x,"
" Response: 0x%02x, t_state: %d\n",
(preempt_and_abort_list) ? "Preempt" : "", tmr_p,
tmr_p->function, tmr_p->response, cmd->t_state);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_cmd_finish_abort_tmr(cmd);
- spin_lock_irq(&dev->se_tmr_lock);
+ transport_cmd_finish_abort(cmd, 1);
}
- spin_unlock_irq(&dev->se_tmr_lock);
+}
+
+static void core_tmr_drain_task_list(
+ struct se_device *dev,
+ struct se_cmd *prout_cmd,
+ struct se_node_acl *tmr_nacl,
+ int tas,
+ struct list_head *preempt_and_abort_list)
+{
+ LIST_HEAD(drain_task_list);
+ struct se_cmd *cmd;
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+ int fe_count;
/*
* Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
* This is following sam4r17, section 5.6 Aborting commands, Table 38
@@ -236,18 +221,28 @@ int core_tmr_lun_reset(
if (prout_cmd == cmd)
continue;
- list_del(&task->t_state_list);
+ list_move_tail(&task->t_state_list, &drain_task_list);
atomic_set(&task->task_state_active, 0);
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ /*
+ * Remove from task execute list before processing drain_task_list
+ */
+ if (!list_empty(&task->t_execute_list))
+ __transport_remove_task_from_execute_queue(task, dev);
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ while (!list_empty(&drain_task_list)) {
+ task = list_entry(drain_task_list.next, struct se_task, t_state_list);
+ list_del(&task->t_state_list);
+ cmd = task->task_se_cmd;
- spin_lock_irqsave(&cmd->t_state_lock, flags);
pr_debug("LUN_RESET: %s cmd: %p task: %p"
- " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/"
- "def_t_state: %d/%d cdb: 0x%02x\n",
+ " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d"
+ "cdb: 0x%02x\n",
(preempt_and_abort_list) ? "Preempt" : "", cmd, task,
cmd->se_tfo->get_task_tag(cmd), 0,
cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
- cmd->deferred_t_state, cmd->t_task_cdb[0]);
+ cmd->t_task_cdb[0]);
pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
" t_task_cdbs: %d t_task_cdbs_left: %d"
" t_task_cdbs_sent: %d -- t_transport_active: %d"
@@ -260,35 +255,24 @@ int core_tmr_lun_reset(
atomic_read(&cmd->t_transport_stop),
atomic_read(&cmd->t_transport_sent));
- if (atomic_read(&task->task_active)) {
- atomic_set(&task->task_stop, 1);
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- pr_debug("LUN_RESET: Waiting for task: %p to shutdown"
- " for dev: %p\n", task, dev);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("LUN_RESET Completed task: %p shutdown for"
- " dev: %p\n", task, dev);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_dec(&cmd->t_task_cdbs_left);
-
- atomic_set(&task->task_active, 0);
- atomic_set(&task->task_stop, 0);
- } else {
- if (atomic_read(&task->task_execute_queue) != 0)
- transport_remove_task_from_execute_queue(task, dev);
- }
- __transport_stop_task_timer(task, &flags);
+ /*
+ * If the command may be queued onto a workqueue cancel it now.
+ *
+ * This is equivalent to removal from the execute queue in the
+ * loop above, but we do it down here given that
+ * cancel_work_sync may block.
+ */
+ if (cmd->t_state == TRANSPORT_COMPLETE)
+ cancel_work_sync(&cmd->work);
+
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ target_stop_task(task, &flags);
if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
pr_debug("LUN_RESET: Skipping task: %p, dev: %p for"
" t_task_cdbs_ex_left: %d\n", task, dev,
atomic_read(&cmd->t_task_cdbs_ex_left));
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
continue;
}
fe_count = atomic_read(&cmd->t_fe_count);
@@ -298,22 +282,31 @@ int core_tmr_lun_reset(
" task: %p, t_fe_count: %d dev: %p\n", task,
fe_count, dev);
atomic_set(&cmd->t_transport_aborted, 1);
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- spin_lock_irqsave(&dev->execute_task_lock, flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
continue;
}
pr_debug("LUN_RESET: Got t_transport_active = 0 for task: %p,"
" t_fe_count: %d dev: %p\n", task, fe_count, dev);
atomic_set(&cmd->t_transport_aborted, 1);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
- spin_lock_irqsave(&dev->execute_task_lock, flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
}
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+}
+
+static void core_tmr_drain_cmd_list(
+ struct se_device *dev,
+ struct se_cmd *prout_cmd,
+ struct se_node_acl *tmr_nacl,
+ int tas,
+ struct list_head *preempt_and_abort_list)
+{
+ LIST_HEAD(drain_cmd_list);
+ struct se_queue_obj *qobj = &dev->dev_queue_obj;
+ struct se_cmd *cmd, *tcmd;
+ unsigned long flags;
/*
* Release all commands remaining in the struct se_device cmd queue.
*
@@ -338,10 +331,15 @@ int core_tmr_lun_reset(
if (prout_cmd == cmd)
continue;
- atomic_dec(&cmd->t_transport_queue_active);
+ atomic_set(&cmd->t_transport_queue_active, 0);
atomic_dec(&qobj->queue_cnt);
- list_del(&cmd->se_queue_node);
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ list_move_tail(&cmd->se_queue_node, &drain_cmd_list);
+ }
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ while (!list_empty(&drain_cmd_list)) {
+ cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node);
+ list_del_init(&cmd->se_queue_node);
pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
" %d t_fe_count: %d\n", (preempt_and_abort_list) ?
@@ -354,9 +352,53 @@ int core_tmr_lun_reset(
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
atomic_read(&cmd->t_fe_count));
- spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
}
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+}
+
+int core_tmr_lun_reset(
+ struct se_device *dev,
+ struct se_tmr_req *tmr,
+ struct list_head *preempt_and_abort_list,
+ struct se_cmd *prout_cmd)
+{
+ struct se_node_acl *tmr_nacl = NULL;
+ struct se_portal_group *tmr_tpg = NULL;
+ int tas;
+ /*
+ * TASK_ABORTED status bit, this is configurable via ConfigFS
+ * struct se_device attributes. spc4r17 section 7.4.6 Control mode page
+ *
+ * A task aborted status (TAS) bit set to zero specifies that aborted
+ * tasks shall be terminated by the device server without any response
+ * to the application client. A TAS bit set to one specifies that tasks
+ * aborted by the actions of an I_T nexus other than the I_T nexus on
+ * which the command was received shall be completed with TASK ABORTED
+ * status (see SAM-4).
+ */
+ tas = dev->se_sub_dev->se_dev_attrib.emulate_tas;
+ /*
+ * Determine if this se_tmr is coming from a $FABRIC_MOD
+ * or struct se_device passthrough..
+ */
+ if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
+ tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
+ tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
+ if (tmr_nacl && tmr_tpg) {
+ pr_debug("LUN_RESET: TMR caller fabric: %s"
+ " initiator port %s\n",
+ tmr_tpg->se_tpg_tfo->get_fabric_name(),
+ tmr_nacl->initiatorname);
+ }
+ }
+ pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n",
+ (preempt_and_abort_list) ? "Preempt" : "TMR",
+ dev->transport->name, tas);
+
+ core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
+ core_tmr_drain_task_list(dev, prout_cmd, tmr_nacl, tas,
+ preempt_and_abort_list);
+ core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas,
+ preempt_and_abort_list);
/*
* Clear any legacy SPC-2 reservation when called during
* LOGICAL UNIT RESET
@@ -379,3 +421,4 @@ int core_tmr_lun_reset(
dev->transport->name);
return 0;
}
+
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 162b736c7342..8ddd133025b9 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -32,6 +32,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/in.h>
+#include <linux/export.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
@@ -593,7 +594,7 @@ int core_tpg_set_initiator_node_queue_depth(
if (init_sess)
tpg->se_tpg_tfo->close_session(init_sess);
- pr_debug("Successfuly changed queue depth to: %d for Initiator"
+ pr_debug("Successfully changed queue depth to: %d for Initiator"
" Node: %s on %s Target Portal Group: %u\n", queue_depth,
initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg));
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index a4b0a8d27f25..3400ae6e93f8 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -26,7 +26,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/net.h>
#include <linux/delay.h>
#include <linux/string.h>
@@ -37,6 +36,7 @@
#include <linux/kthread.h>
#include <linux/in.h>
#include <linux/cdrom.h>
+#include <linux/module.h>
#include <asm/unaligned.h>
#include <net/sock.h>
#include <net/tcp.h>
@@ -53,13 +53,14 @@
#include <target/target_core_configfs.h>
#include "target_core_alua.h"
+#include "target_core_cdb.h"
#include "target_core_hba.h"
#include "target_core_pr.h"
-#include "target_core_scdb.h"
#include "target_core_ua.h"
static int sub_api_initialized;
+static struct workqueue_struct *target_completion_wq;
static struct kmem_cache *se_cmd_cache;
static struct kmem_cache *se_sess_cache;
struct kmem_cache *se_tmr_req_cache;
@@ -70,30 +71,19 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache;
struct kmem_cache *t10_alua_tg_pt_gp_cache;
struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
-/* Used for transport_dev_get_map_*() */
-typedef int (*map_func_t)(struct se_task *, u32);
-
static int transport_generic_write_pending(struct se_cmd *);
static int transport_processing_thread(void *param);
static int __transport_execute_tasks(struct se_device *dev);
static void transport_complete_task_attr(struct se_cmd *cmd);
-static int transport_complete_qf(struct se_cmd *cmd);
static void transport_handle_queue_full(struct se_cmd *cmd,
- struct se_device *dev, int (*qf_callback)(struct se_cmd *));
-static void transport_direct_request_timeout(struct se_cmd *cmd);
+ struct se_device *dev);
static void transport_free_dev_tasks(struct se_cmd *cmd);
-static u32 transport_allocate_tasks(struct se_cmd *cmd,
- unsigned long long starting_lba,
- enum dma_data_direction data_direction,
- struct scatterlist *sgl, unsigned int nents);
static int transport_generic_get_mem(struct se_cmd *cmd);
-static int transport_generic_remove(struct se_cmd *cmd,
- int session_reinstatement);
-static void transport_release_fe_cmd(struct se_cmd *cmd);
-static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
- struct se_queue_obj *qobj);
+static void transport_put_cmd(struct se_cmd *cmd);
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd);
static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);
-static void transport_stop_all_task_timers(struct se_cmd *cmd);
+static void transport_generic_request_failure(struct se_cmd *, int, int);
+static void target_complete_ok_work(struct work_struct *work);
int init_se_kmem_caches(void)
{
@@ -109,7 +99,7 @@ int init_se_kmem_caches(void)
if (!se_tmr_req_cache) {
pr_err("kmem_cache_create() for struct se_tmr_req"
" failed\n");
- goto out;
+ goto out_free_cmd_cache;
}
se_sess_cache = kmem_cache_create("se_sess_cache",
sizeof(struct se_session), __alignof__(struct se_session),
@@ -117,14 +107,14 @@ int init_se_kmem_caches(void)
if (!se_sess_cache) {
pr_err("kmem_cache_create() for struct se_session"
" failed\n");
- goto out;
+ goto out_free_tmr_req_cache;
}
se_ua_cache = kmem_cache_create("se_ua_cache",
sizeof(struct se_ua), __alignof__(struct se_ua),
0, NULL);
if (!se_ua_cache) {
pr_err("kmem_cache_create() for struct se_ua failed\n");
- goto out;
+ goto out_free_sess_cache;
}
t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache",
sizeof(struct t10_pr_registration),
@@ -132,7 +122,7 @@ int init_se_kmem_caches(void)
if (!t10_pr_reg_cache) {
pr_err("kmem_cache_create() for struct t10_pr_registration"
" failed\n");
- goto out;
+ goto out_free_ua_cache;
}
t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache",
sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp),
@@ -140,7 +130,7 @@ int init_se_kmem_caches(void)
if (!t10_alua_lu_gp_cache) {
pr_err("kmem_cache_create() for t10_alua_lu_gp_cache"
" failed\n");
- goto out;
+ goto out_free_pr_reg_cache;
}
t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache",
sizeof(struct t10_alua_lu_gp_member),
@@ -148,7 +138,7 @@ int init_se_kmem_caches(void)
if (!t10_alua_lu_gp_mem_cache) {
pr_err("kmem_cache_create() for t10_alua_lu_gp_mem_"
"cache failed\n");
- goto out;
+ goto out_free_lu_gp_cache;
}
t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache",
sizeof(struct t10_alua_tg_pt_gp),
@@ -156,7 +146,7 @@ int init_se_kmem_caches(void)
if (!t10_alua_tg_pt_gp_cache) {
pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_"
"cache failed\n");
- goto out;
+ goto out_free_lu_gp_mem_cache;
}
t10_alua_tg_pt_gp_mem_cache = kmem_cache_create(
"t10_alua_tg_pt_gp_mem_cache",
@@ -166,34 +156,41 @@ int init_se_kmem_caches(void)
if (!t10_alua_tg_pt_gp_mem_cache) {
pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_"
"mem_t failed\n");
- goto out;
+ goto out_free_tg_pt_gp_cache;
}
+ target_completion_wq = alloc_workqueue("target_completion",
+ WQ_MEM_RECLAIM, 0);
+ if (!target_completion_wq)
+ goto out_free_tg_pt_gp_mem_cache;
+
return 0;
+
+out_free_tg_pt_gp_mem_cache:
+ kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+out_free_tg_pt_gp_cache:
+ kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+out_free_lu_gp_mem_cache:
+ kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
+out_free_lu_gp_cache:
+ kmem_cache_destroy(t10_alua_lu_gp_cache);
+out_free_pr_reg_cache:
+ kmem_cache_destroy(t10_pr_reg_cache);
+out_free_ua_cache:
+ kmem_cache_destroy(se_ua_cache);
+out_free_sess_cache:
+ kmem_cache_destroy(se_sess_cache);
+out_free_tmr_req_cache:
+ kmem_cache_destroy(se_tmr_req_cache);
+out_free_cmd_cache:
+ kmem_cache_destroy(se_cmd_cache);
out:
- if (se_cmd_cache)
- kmem_cache_destroy(se_cmd_cache);
- if (se_tmr_req_cache)
- kmem_cache_destroy(se_tmr_req_cache);
- if (se_sess_cache)
- kmem_cache_destroy(se_sess_cache);
- if (se_ua_cache)
- kmem_cache_destroy(se_ua_cache);
- if (t10_pr_reg_cache)
- kmem_cache_destroy(t10_pr_reg_cache);
- if (t10_alua_lu_gp_cache)
- kmem_cache_destroy(t10_alua_lu_gp_cache);
- if (t10_alua_lu_gp_mem_cache)
- kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
- if (t10_alua_tg_pt_gp_cache)
- kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
- if (t10_alua_tg_pt_gp_mem_cache)
- kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
return -ENOMEM;
}
void release_se_kmem_caches(void)
{
+ destroy_workqueue(target_completion_wq);
kmem_cache_destroy(se_cmd_cache);
kmem_cache_destroy(se_tmr_req_cache);
kmem_cache_destroy(se_sess_cache);
@@ -234,10 +231,13 @@ void transport_init_queue_obj(struct se_queue_obj *qobj)
}
EXPORT_SYMBOL(transport_init_queue_obj);
-static int transport_subsystem_reqmods(void)
+void transport_subsystem_check_init(void)
{
int ret;
+ if (sub_api_initialized)
+ return;
+
ret = request_module("target_core_iblock");
if (ret != 0)
pr_err("Unable to load target_core_iblock\n");
@@ -254,24 +254,8 @@ static int transport_subsystem_reqmods(void)
if (ret != 0)
pr_err("Unable to load target_core_stgt\n");
- return 0;
-}
-
-int transport_subsystem_check_init(void)
-{
- int ret;
-
- if (sub_api_initialized)
- return 0;
- /*
- * Request the loading of known TCM subsystem plugins..
- */
- ret = transport_subsystem_reqmods();
- if (ret < 0)
- return ret;
-
sub_api_initialized = 1;
- return 0;
+ return;
}
struct se_session *transport_init_session(void)
@@ -286,6 +270,9 @@ struct se_session *transport_init_session(void)
}
INIT_LIST_HEAD(&se_sess->sess_list);
INIT_LIST_HEAD(&se_sess->sess_acl_list);
+ INIT_LIST_HEAD(&se_sess->sess_cmd_list);
+ INIT_LIST_HEAD(&se_sess->sess_wait_list);
+ spin_lock_init(&se_sess->sess_cmd_lock);
return se_sess;
}
@@ -438,16 +425,15 @@ EXPORT_SYMBOL(transport_deregister_session);
*/
static void transport_all_task_dev_remove_state(struct se_cmd *cmd)
{
- struct se_device *dev;
+ struct se_device *dev = cmd->se_dev;
struct se_task *task;
unsigned long flags;
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- dev = task->se_dev;
- if (!dev)
- continue;
+ if (!dev)
+ return;
- if (atomic_read(&task->task_active))
+ list_for_each_entry(task, &cmd->t_task_list, t_list) {
+ if (task->task_flags & TF_ACTIVE)
continue;
if (!atomic_read(&task->task_state_active))
@@ -489,8 +475,6 @@ static int transport_cmd_check_stop(
" == TRUE for ITT: 0x%08x\n", __func__, __LINE__,
cmd->se_tfo->get_task_tag(cmd));
- cmd->deferred_t_state = cmd->t_state;
- cmd->t_state = TRANSPORT_DEFERRED_CMD;
atomic_set(&cmd->t_transport_active, 0);
if (transport_off == 2)
transport_all_task_dev_remove_state(cmd);
@@ -508,8 +492,6 @@ static int transport_cmd_check_stop(
" TRUE for ITT: 0x%08x\n", __func__, __LINE__,
cmd->se_tfo->get_task_tag(cmd));
- cmd->deferred_t_state = cmd->t_state;
- cmd->t_state = TRANSPORT_DEFERRED_CMD;
if (transport_off == 2)
transport_all_task_dev_remove_state(cmd);
@@ -537,13 +519,16 @@ static int transport_cmd_check_stop(
* Some fabric modules like tcm_loop can release
* their internally allocated I/O reference now and
* struct se_cmd now.
+ *
+ * Fabric modules are expected to return '1' here if the
+ * se_cmd being passed is released at this point,
+ * or zero if not being released.
*/
if (cmd->se_tfo->check_stop_free != NULL) {
spin_unlock_irqrestore(
&cmd->t_state_lock, flags);
- cmd->se_tfo->check_stop_free(cmd);
- return 1;
+ return cmd->se_tfo->check_stop_free(cmd);
}
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -594,35 +579,24 @@ check_lun:
void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
{
- transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj);
- transport_lun_remove_cmd(cmd);
+ if (!cmd->se_tmr_req)
+ transport_lun_remove_cmd(cmd);
if (transport_cmd_check_stop_to_fabric(cmd))
return;
- if (remove)
- transport_generic_remove(cmd, 0);
-}
-
-void transport_cmd_finish_abort_tmr(struct se_cmd *cmd)
-{
- transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj);
-
- if (transport_cmd_check_stop_to_fabric(cmd))
- return;
-
- transport_generic_remove(cmd, 0);
+ if (remove) {
+ transport_remove_cmd_from_queue(cmd);
+ transport_put_cmd(cmd);
+ }
}
-static void transport_add_cmd_to_queue(
- struct se_cmd *cmd,
- int t_state)
+static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state,
+ bool at_head)
{
struct se_device *dev = cmd->se_dev;
struct se_queue_obj *qobj = &dev->dev_queue_obj;
unsigned long flags;
- INIT_LIST_HEAD(&cmd->se_queue_node);
-
if (t_state) {
spin_lock_irqsave(&cmd->t_state_lock, flags);
cmd->t_state = t_state;
@@ -631,15 +605,20 @@ static void transport_add_cmd_to_queue(
}
spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
- if (cmd->se_cmd_flags & SCF_EMULATE_QUEUE_FULL) {
- cmd->se_cmd_flags &= ~SCF_EMULATE_QUEUE_FULL;
+
+ /* If the cmd is already on the list, remove it before we add it */
+ if (!list_empty(&cmd->se_queue_node))
+ list_del(&cmd->se_queue_node);
+ else
+ atomic_inc(&qobj->queue_cnt);
+
+ if (at_head)
list_add(&cmd->se_queue_node, &qobj->qobj_list);
- } else
+ else
list_add_tail(&cmd->se_queue_node, &qobj->qobj_list);
- atomic_inc(&cmd->t_transport_queue_active);
+ atomic_set(&cmd->t_transport_queue_active, 1);
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
- atomic_inc(&qobj->queue_cnt);
wake_up_interruptible(&qobj->thread_wq);
}
@@ -656,19 +635,18 @@ transport_get_cmd_from_queue(struct se_queue_obj *qobj)
}
cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node);
- atomic_dec(&cmd->t_transport_queue_active);
+ atomic_set(&cmd->t_transport_queue_active, 0);
- list_del(&cmd->se_queue_node);
+ list_del_init(&cmd->se_queue_node);
atomic_dec(&qobj->queue_cnt);
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
return cmd;
}
-static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
- struct se_queue_obj *qobj)
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd)
{
- struct se_cmd *t;
+ struct se_queue_obj *qobj = &cmd->se_dev->dev_queue_obj;
unsigned long flags;
spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
@@ -676,14 +654,9 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
return;
}
-
- list_for_each_entry(t, &qobj->qobj_list, se_queue_node)
- if (t == cmd) {
- atomic_dec(&cmd->t_transport_queue_active);
- atomic_dec(&qobj->queue_cnt);
- list_del(&cmd->se_queue_node);
- break;
- }
+ atomic_set(&cmd->t_transport_queue_active, 0);
+ atomic_dec(&qobj->queue_cnt);
+ list_del_init(&cmd->se_queue_node);
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
if (atomic_read(&cmd->t_transport_queue_active)) {
@@ -716,6 +689,13 @@ void transport_complete_sync_cache(struct se_cmd *cmd, int good)
}
EXPORT_SYMBOL(transport_complete_sync_cache);
+static void target_complete_failure_work(struct work_struct *work)
+{
+ struct se_cmd *cmd = container_of(work, struct se_cmd, work);
+
+ transport_generic_request_failure(cmd, 1, 1);
+}
+
/* transport_complete_task():
*
* Called from interrupt and non interrupt context depending
@@ -724,8 +704,7 @@ EXPORT_SYMBOL(transport_complete_sync_cache);
void transport_complete_task(struct se_task *task, int success)
{
struct se_cmd *cmd = task->task_se_cmd;
- struct se_device *dev = task->se_dev;
- int t_state;
+ struct se_device *dev = cmd->se_dev;
unsigned long flags;
#if 0
pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task,
@@ -735,7 +714,7 @@ void transport_complete_task(struct se_task *task, int success)
atomic_inc(&dev->depth_left);
spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_set(&task->task_active, 0);
+ task->task_flags &= ~TF_ACTIVE;
/*
* See if any sense data exists, if so set the TASK_SENSE flag.
@@ -754,39 +733,14 @@ void transport_complete_task(struct se_task *task, int success)
* See if we are waiting for outstanding struct se_task
* to complete for an exception condition
*/
- if (atomic_read(&task->task_stop)) {
- /*
- * Decrement cmd->t_se_count if this task had
- * previously thrown its timeout exception handler.
- */
- if (atomic_read(&task->task_timeout)) {
- atomic_dec(&cmd->t_se_count);
- atomic_set(&task->task_timeout, 0);
- }
+ if (task->task_flags & TF_REQUEST_STOP) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
complete(&task->task_stop_comp);
return;
}
- /*
- * If the task's timeout handler has fired, use the t_task_cdbs_timeout
- * left counter to determine when the struct se_cmd is ready to be queued to
- * the processing thread.
- */
- if (atomic_read(&task->task_timeout)) {
- if (!atomic_dec_and_test(
- &cmd->t_task_cdbs_timeout_left)) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- return;
- }
- t_state = TRANSPORT_COMPLETE_TIMEOUT;
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_add_cmd_to_queue(cmd, t_state);
- return;
- }
- atomic_dec(&cmd->t_task_cdbs_timeout_left);
+ if (!success)
+ cmd->t_tasks_failed = 1;
/*
* Decrement the outstanding t_task_cdbs_left count. The last
@@ -794,28 +748,28 @@ void transport_complete_task(struct se_task *task, int success)
* device queue depending upon int success.
*/
if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) {
- if (!success)
- cmd->t_tasks_failed = 1;
-
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return;
}
- if (!success || cmd->t_tasks_failed) {
- t_state = TRANSPORT_COMPLETE_FAILURE;
+ if (cmd->t_tasks_failed) {
if (!task->task_error_status) {
task->task_error_status =
PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
cmd->transport_error_status =
PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
+ INIT_WORK(&cmd->work, target_complete_failure_work);
} else {
atomic_set(&cmd->t_transport_complete, 1);
- t_state = TRANSPORT_COMPLETE_OK;
+ INIT_WORK(&cmd->work, target_complete_ok_work);
}
+
+ cmd->t_state = TRANSPORT_COMPLETE;
+ atomic_set(&cmd->t_transport_active, 1);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_add_cmd_to_queue(cmd, t_state);
+ queue_work(target_completion_wq, &cmd->work);
}
EXPORT_SYMBOL(transport_complete_task);
@@ -902,14 +856,12 @@ static void __transport_add_task_to_execute_queue(
static void transport_add_tasks_to_state_queue(struct se_cmd *cmd)
{
- struct se_device *dev;
+ struct se_device *dev = cmd->se_dev;
struct se_task *task;
unsigned long flags;
spin_lock_irqsave(&cmd->t_state_lock, flags);
list_for_each_entry(task, &cmd->t_task_list, t_list) {
- dev = task->se_dev;
-
if (atomic_read(&task->task_state_active))
continue;
@@ -934,43 +886,41 @@ static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
spin_lock_irqsave(&dev->execute_task_lock, flags);
list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (atomic_read(&task->task_execute_queue))
+ if (!list_empty(&task->t_execute_list))
continue;
/*
* __transport_add_task_to_execute_queue() handles the
* SAM Task Attribute emulation if enabled
*/
__transport_add_task_to_execute_queue(task, task_prev, dev);
- atomic_set(&task->task_execute_queue, 1);
task_prev = task;
}
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
-/* transport_remove_task_from_execute_queue():
- *
- *
- */
+void __transport_remove_task_from_execute_queue(struct se_task *task,
+ struct se_device *dev)
+{
+ list_del_init(&task->t_execute_list);
+ atomic_dec(&dev->execute_tasks);
+}
+
void transport_remove_task_from_execute_queue(
struct se_task *task,
struct se_device *dev)
{
unsigned long flags;
- if (atomic_read(&task->task_execute_queue) == 0) {
- dump_stack();
+ if (WARN_ON(list_empty(&task->t_execute_list)))
return;
- }
spin_lock_irqsave(&dev->execute_task_lock, flags);
- list_del(&task->t_execute_list);
- atomic_set(&task->task_execute_queue, 0);
- atomic_dec(&dev->execute_tasks);
+ __transport_remove_task_from_execute_queue(task, dev);
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
/*
- * Handle QUEUE_FULL / -EAGAIN status
+ * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status
*/
static void target_qf_do_work(struct work_struct *work)
@@ -991,14 +941,11 @@ static void target_qf_do_work(struct work_struct *work)
pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue"
" context: %s\n", cmd->se_tfo->get_fabric_name(), cmd,
- (cmd->t_state == TRANSPORT_COMPLETE_OK) ? "COMPLETE_OK" :
+ (cmd->t_state == TRANSPORT_COMPLETE_QF_OK) ? "COMPLETE_OK" :
(cmd->t_state == TRANSPORT_COMPLETE_QF_WP) ? "WRITE_PENDING"
: "UNKNOWN");
- /*
- * The SCF_EMULATE_QUEUE_FULL flag will be cleared once se_cmd
- * has been added to head of queue
- */
- transport_add_cmd_to_queue(cmd, cmd->t_state);
+
+ transport_add_cmd_to_queue(cmd, cmd->t_state, true);
}
}
@@ -1053,41 +1000,6 @@ void transport_dump_dev_state(
*bl += sprintf(b + *bl, " ");
}
-/* transport_release_all_cmds():
- *
- *
- */
-static void transport_release_all_cmds(struct se_device *dev)
-{
- struct se_cmd *cmd, *tcmd;
- int bug_out = 0, t_state;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->dev_queue_obj.cmd_queue_lock, flags);
- list_for_each_entry_safe(cmd, tcmd, &dev->dev_queue_obj.qobj_list,
- se_queue_node) {
- t_state = cmd->t_state;
- list_del(&cmd->se_queue_node);
- spin_unlock_irqrestore(&dev->dev_queue_obj.cmd_queue_lock,
- flags);
-
- pr_err("Releasing ITT: 0x%08x, i_state: %u,"
- " t_state: %u directly\n",
- cmd->se_tfo->get_task_tag(cmd),
- cmd->se_tfo->get_cmd_state(cmd), t_state);
-
- transport_release_fe_cmd(cmd);
- bug_out = 1;
-
- spin_lock_irqsave(&dev->dev_queue_obj.cmd_queue_lock, flags);
- }
- spin_unlock_irqrestore(&dev->dev_queue_obj.cmd_queue_lock, flags);
-#if 0
- if (bug_out)
- BUG();
-#endif
-}
-
void transport_dump_vpd_proto_id(
struct t10_vpd *vpd,
unsigned char *p_buf,
@@ -1573,7 +1485,6 @@ transport_generic_get_task(struct se_cmd *cmd,
INIT_LIST_HEAD(&task->t_state_list);
init_completion(&task->task_stop_comp);
task->task_se_cmd = cmd;
- task->se_dev = dev;
task->task_data_direction = data_direction;
return task;
@@ -1598,11 +1509,13 @@ void transport_init_se_cmd(
INIT_LIST_HEAD(&cmd->se_delayed_node);
INIT_LIST_HEAD(&cmd->se_ordered_node);
INIT_LIST_HEAD(&cmd->se_qf_node);
-
+ INIT_LIST_HEAD(&cmd->se_queue_node);
+ INIT_LIST_HEAD(&cmd->se_cmd_list);
INIT_LIST_HEAD(&cmd->t_task_list);
init_completion(&cmd->transport_lun_fe_stop_comp);
init_completion(&cmd->transport_lun_stop_comp);
init_completion(&cmd->t_transport_stop_comp);
+ init_completion(&cmd->cmd_wait_comp);
spin_lock_init(&cmd->t_state_lock);
atomic_set(&cmd->transport_dev_active, 1);
@@ -1641,21 +1554,6 @@ static int transport_check_alloc_task_attr(struct se_cmd *cmd)
return 0;
}
-void transport_free_se_cmd(
- struct se_cmd *se_cmd)
-{
- if (se_cmd->se_tmr_req)
- core_tmr_release_req(se_cmd->se_tmr_req);
- /*
- * Check and free any extended CDB buffer that was allocated
- */
- if (se_cmd->t_task_cdb != se_cmd->__t_task_cdb)
- kfree(se_cmd->t_task_cdb);
-}
-EXPORT_SYMBOL(transport_free_se_cmd);
-
-static void transport_generic_wait_for_tasks(struct se_cmd *, int, int);
-
/* transport_generic_allocate_tasks():
*
* Called from fabric RX Thread.
@@ -1667,12 +1565,6 @@ int transport_generic_allocate_tasks(
int ret;
transport_generic_prepare_cdb(cdb);
-
- /*
- * This is needed for early exceptions.
- */
- cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
-
/*
* Ensure that the received CDB is less than the max (252 + 8) bytes
* for VARIABLE_LENGTH_CMD
@@ -1730,26 +1622,6 @@ int transport_generic_allocate_tasks(
EXPORT_SYMBOL(transport_generic_allocate_tasks);
/*
- * Used by fabric module frontends not defining a TFO->new_cmd_map()
- * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD statis
- */
-int transport_generic_handle_cdb(
- struct se_cmd *cmd)
-{
- if (!cmd->se_lun) {
- dump_stack();
- pr_err("cmd->se_lun is NULL\n");
- return -EINVAL;
- }
-
- transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD);
- return 0;
-}
-EXPORT_SYMBOL(transport_generic_handle_cdb);
-
-static void transport_generic_request_failure(struct se_cmd *,
- struct se_device *, int, int);
-/*
* Used by fabric module frontends to queue tasks directly.
* Many only be used from process context only
*/
@@ -1773,7 +1645,7 @@ int transport_handle_cdb_direct(
* Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following
* transport_generic_handle_cdb*() -> transport_add_cmd_to_queue()
* in existing usage to ensure that outstanding descriptors are handled
- * correctly during shutdown via transport_generic_wait_for_tasks()
+ * correctly during shutdown via transport_wait_for_tasks()
*
* Also, we don't take cmd->t_state_lock here as we only expect
* this to be called for initial descriptor submission.
@@ -1786,11 +1658,9 @@ int transport_handle_cdb_direct(
* and call transport_generic_request_failure() if necessary..
*/
ret = transport_generic_new_cmd(cmd);
- if (ret == -EAGAIN)
- return 0;
- else if (ret < 0) {
+ if (ret < 0) {
cmd->transport_error_status = ret;
- transport_generic_request_failure(cmd, NULL, 0,
+ transport_generic_request_failure(cmd, 0,
(cmd->data_direction != DMA_TO_DEVICE));
}
return 0;
@@ -1811,7 +1681,7 @@ int transport_generic_handle_cdb_map(
return -EINVAL;
}
- transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP, false);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_cdb_map);
@@ -1841,7 +1711,7 @@ int transport_generic_handle_data(
if (transport_check_aborted_status(cmd, 1) != 0)
return 0;
- transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE, false);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_data);
@@ -1853,22 +1723,36 @@ EXPORT_SYMBOL(transport_generic_handle_data);
int transport_generic_handle_tmr(
struct se_cmd *cmd)
{
- /*
- * This is needed for early exceptions.
- */
- cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
-
- transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR, false);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_tmr);
-void transport_generic_free_cmd_intr(
- struct se_cmd *cmd)
+/*
+ * If the task is active, request it to be stopped and sleep until it
+ * has completed.
+ */
+bool target_stop_task(struct se_task *task, unsigned long *flags)
{
- transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR);
+ struct se_cmd *cmd = task->task_se_cmd;
+ bool was_active = false;
+
+ if (task->task_flags & TF_ACTIVE) {
+ task->task_flags |= TF_REQUEST_STOP;
+ spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
+
+ pr_debug("Task %p waiting to complete\n", task);
+ wait_for_completion(&task->task_stop_comp);
+ pr_debug("Task %p stopped successfully\n", task);
+
+ spin_lock_irqsave(&cmd->t_state_lock, *flags);
+ atomic_dec(&cmd->t_task_cdbs_left);
+ task->task_flags &= ~(TF_ACTIVE | TF_REQUEST_STOP);
+ was_active = true;
+ }
+
+ return was_active;
}
-EXPORT_SYMBOL(transport_generic_free_cmd_intr);
static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
{
@@ -1885,51 +1769,26 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
spin_lock_irqsave(&cmd->t_state_lock, flags);
list_for_each_entry_safe(task, task_tmp,
&cmd->t_task_list, t_list) {
- pr_debug("task_no[%d] - Processing task %p\n",
- task->task_no, task);
+ pr_debug("Processing task %p\n", task);
/*
* If the struct se_task has not been sent and is not active,
* remove the struct se_task from the execution queue.
*/
- if (!atomic_read(&task->task_sent) &&
- !atomic_read(&task->task_active)) {
+ if (!(task->task_flags & (TF_ACTIVE | TF_SENT))) {
spin_unlock_irqrestore(&cmd->t_state_lock,
flags);
transport_remove_task_from_execute_queue(task,
- task->se_dev);
+ cmd->se_dev);
- pr_debug("task_no[%d] - Removed from execute queue\n",
- task->task_no);
+ pr_debug("Task %p removed from execute queue\n", task);
spin_lock_irqsave(&cmd->t_state_lock, flags);
continue;
}
- /*
- * If the struct se_task is active, sleep until it is returned
- * from the plugin.
- */
- if (atomic_read(&task->task_active)) {
- atomic_set(&task->task_stop, 1);
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
-
- pr_debug("task_no[%d] - Waiting to complete\n",
- task->task_no);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("task_no[%d] - Stopped successfully\n",
- task->task_no);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_dec(&cmd->t_task_cdbs_left);
-
- atomic_set(&task->task_active, 0);
- atomic_set(&task->task_stop, 0);
- } else {
- pr_debug("task_no[%d] - Did nothing\n", task->task_no);
+ if (!target_stop_task(task, &flags)) {
+ pr_debug("Task %p - did nothing\n", task);
ret++;
}
-
- __transport_stop_task_timer(task, &flags);
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -1941,7 +1800,6 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
*/
static void transport_generic_request_failure(
struct se_cmd *cmd,
- struct se_device *dev,
int complete,
int sc)
{
@@ -1950,10 +1808,9 @@ static void transport_generic_request_failure(
pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x"
" CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd),
cmd->t_task_cdb[0]);
- pr_debug("-----[ i_state: %d t_state/def_t_state:"
- " %d/%d transport_error_status: %d\n",
+ pr_debug("-----[ i_state: %d t_state: %d transport_error_status: %d\n",
cmd->se_tfo->get_cmd_state(cmd),
- cmd->t_state, cmd->deferred_t_state,
+ cmd->t_state,
cmd->transport_error_status);
pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d"
" t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --"
@@ -1966,10 +1823,6 @@ static void transport_generic_request_failure(
atomic_read(&cmd->t_transport_stop),
atomic_read(&cmd->t_transport_sent));
- transport_stop_all_task_timers(cmd);
-
- if (dev)
- atomic_inc(&dev->depth_left);
/*
* For SAM Task Attribute emulation for failed struct se_cmd
*/
@@ -1977,7 +1830,6 @@ static void transport_generic_request_failure(
transport_complete_task_attr(cmd);
if (complete) {
- transport_direct_request_timeout(cmd);
cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE;
}
@@ -2038,7 +1890,7 @@ static void transport_generic_request_failure(
ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
ret = cmd->se_tfo->queue_status(cmd);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
goto check_stop;
case PYX_TRANSPORT_USE_SENSE_REASON:
@@ -2065,7 +1917,7 @@ static void transport_generic_request_failure(
else {
ret = transport_send_check_condition_and_sense(cmd,
cmd->scsi_sense_reason, 0);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
}
@@ -2076,46 +1928,8 @@ check_stop:
return;
queue_full:
- cmd->t_state = TRANSPORT_COMPLETE_OK;
- transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf);
-}
-
-static void transport_direct_request_timeout(struct se_cmd *cmd)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (!atomic_read(&cmd->t_transport_timeout)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- if (atomic_read(&cmd->t_task_cdbs_timeout_left)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
-
- atomic_sub(atomic_read(&cmd->t_transport_timeout),
- &cmd->t_se_count);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-}
-
-static void transport_generic_request_timeout(struct se_cmd *cmd)
-{
- unsigned long flags;
-
- /*
- * Reset cmd->t_se_count to allow transport_generic_remove()
- * to allow last call to free memory resources.
- */
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (atomic_read(&cmd->t_transport_timeout) > 1) {
- int tmp = (atomic_read(&cmd->t_transport_timeout) - 1);
-
- atomic_sub(tmp, &cmd->t_se_count);
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- transport_generic_remove(cmd, 0);
+ cmd->t_state = TRANSPORT_COMPLETE_QF_OK;
+ transport_handle_queue_full(cmd, cmd->se_dev);
}
static inline u32 transport_lba_21(unsigned char *cdb)
@@ -2160,127 +1974,6 @@ static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
}
-/*
- * Called from interrupt context.
- */
-static void transport_task_timeout_handler(unsigned long data)
-{
- struct se_task *task = (struct se_task *)data;
- struct se_cmd *cmd = task->task_se_cmd;
- unsigned long flags;
-
- pr_debug("transport task timeout fired! task: %p cmd: %p\n", task, cmd);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (task->task_flags & TF_STOP) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- task->task_flags &= ~TF_RUNNING;
-
- /*
- * Determine if transport_complete_task() has already been called.
- */
- if (!atomic_read(&task->task_active)) {
- pr_debug("transport task: %p cmd: %p timeout task_active"
- " == 0\n", task, cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
-
- atomic_inc(&cmd->t_se_count);
- atomic_inc(&cmd->t_transport_timeout);
- cmd->t_tasks_failed = 1;
-
- atomic_set(&task->task_timeout, 1);
- task->task_error_status = PYX_TRANSPORT_TASK_TIMEOUT;
- task->task_scsi_status = 1;
-
- if (atomic_read(&task->task_stop)) {
- pr_debug("transport task: %p cmd: %p timeout task_stop"
- " == 1\n", task, cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- complete(&task->task_stop_comp);
- return;
- }
-
- if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) {
- pr_debug("transport task: %p cmd: %p timeout non zero"
- " t_task_cdbs_left\n", task, cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- pr_debug("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n",
- task, cmd);
-
- cmd->t_state = TRANSPORT_COMPLETE_FAILURE;
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE);
-}
-
-/*
- * Called with cmd->t_state_lock held.
- */
-static void transport_start_task_timer(struct se_task *task)
-{
- struct se_device *dev = task->se_dev;
- int timeout;
-
- if (task->task_flags & TF_RUNNING)
- return;
- /*
- * If the task_timeout is disabled, exit now.
- */
- timeout = dev->se_sub_dev->se_dev_attrib.task_timeout;
- if (!timeout)
- return;
-
- init_timer(&task->task_timer);
- task->task_timer.expires = (get_jiffies_64() + timeout * HZ);
- task->task_timer.data = (unsigned long) task;
- task->task_timer.function = transport_task_timeout_handler;
-
- task->task_flags |= TF_RUNNING;
- add_timer(&task->task_timer);
-#if 0
- pr_debug("Starting task timer for cmd: %p task: %p seconds:"
- " %d\n", task->task_se_cmd, task, timeout);
-#endif
-}
-
-/*
- * Called with spin_lock_irq(&cmd->t_state_lock) held.
- */
-void __transport_stop_task_timer(struct se_task *task, unsigned long *flags)
-{
- struct se_cmd *cmd = task->task_se_cmd;
-
- if (!task->task_flags & TF_RUNNING)
- return;
-
- task->task_flags |= TF_STOP;
- spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
-
- del_timer_sync(&task->task_timer);
-
- spin_lock_irqsave(&cmd->t_state_lock, *flags);
- task->task_flags &= ~TF_RUNNING;
- task->task_flags &= ~TF_STOP;
-}
-
-static void transport_stop_all_task_timers(struct se_cmd *cmd)
-{
- struct se_task *task = NULL, *task_tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_for_each_entry_safe(task, task_tmp,
- &cmd->t_task_list, t_list)
- __transport_stop_task_timer(task, &flags);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-}
-
static inline int transport_tcq_window_closed(struct se_device *dev)
{
if (dev->dev_tcq_window_closed++ <
@@ -2385,7 +2078,7 @@ static int transport_execute_tasks(struct se_cmd *cmd)
if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) {
cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE;
- transport_generic_request_failure(cmd, NULL, 0, 1);
+ transport_generic_request_failure(cmd, 0, 1);
return 0;
}
@@ -2448,9 +2141,7 @@ check_depth:
}
task = list_first_entry(&dev->execute_task_list,
struct se_task, t_execute_list);
- list_del(&task->t_execute_list);
- atomic_set(&task->task_execute_queue, 0);
- atomic_dec(&dev->execute_tasks);
+ __transport_remove_task_from_execute_queue(task, dev);
spin_unlock_irq(&dev->execute_task_lock);
atomic_dec(&dev->depth_left);
@@ -2458,66 +2149,28 @@ check_depth:
cmd = task->task_se_cmd;
spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_set(&task->task_active, 1);
- atomic_set(&task->task_sent, 1);
+ task->task_flags |= (TF_ACTIVE | TF_SENT);
atomic_inc(&cmd->t_task_cdbs_sent);
if (atomic_read(&cmd->t_task_cdbs_sent) ==
cmd->t_task_list_num)
- atomic_set(&cmd->transport_sent, 1);
+ atomic_set(&cmd->t_transport_sent, 1);
- transport_start_task_timer(task);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- /*
- * The struct se_cmd->transport_emulate_cdb() function pointer is used
- * to grab REPORT_LUNS and other CDBs we want to handle before they hit the
- * struct se_subsystem_api->do_task() caller below.
- */
- if (cmd->transport_emulate_cdb) {
- error = cmd->transport_emulate_cdb(cmd);
- if (error != 0) {
- cmd->transport_error_status = error;
- atomic_set(&task->task_active, 0);
- atomic_set(&cmd->transport_sent, 0);
- transport_stop_tasks_for_cmd(cmd);
- transport_generic_request_failure(cmd, dev, 0, 1);
- goto check_depth;
- }
- /*
- * Handle the successful completion for transport_emulate_cdb()
- * for synchronous operation, following SCF_EMULATE_CDB_ASYNC
- * Otherwise the caller is expected to complete the task with
- * proper status.
- */
- if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
- cmd->scsi_status = SAM_STAT_GOOD;
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
- } else {
- /*
- * Currently for all virtual TCM plugins including IBLOCK, FILEIO and
- * RAMDISK we use the internal transport_emulate_control_cdb() logic
- * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK
- * LUN emulation code.
- *
- * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we
- * call ->do_task() directly and let the underlying TCM subsystem plugin
- * code handle the CDB emulation.
- */
- if ((dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) &&
- (!(task->task_se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
- error = transport_emulate_control_cdb(task);
- else
- error = dev->transport->do_task(task);
-
- if (error != 0) {
- cmd->transport_error_status = error;
- atomic_set(&task->task_active, 0);
- atomic_set(&cmd->transport_sent, 0);
- transport_stop_tasks_for_cmd(cmd);
- transport_generic_request_failure(cmd, dev, 0, 1);
- }
+
+ if (cmd->execute_task)
+ error = cmd->execute_task(task);
+ else
+ error = dev->transport->do_task(task);
+ if (error != 0) {
+ cmd->transport_error_status = error;
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ task->task_flags &= ~TF_ACTIVE;
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ atomic_set(&cmd->t_transport_sent, 0);
+ transport_stop_tasks_for_cmd(cmd);
+ atomic_inc(&dev->depth_left);
+ transport_generic_request_failure(cmd, 0, 1);
}
goto check_depth;
@@ -2538,8 +2191,6 @@ void transport_new_cmd_failure(struct se_cmd *se_cmd)
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
}
-static void transport_nop_wait_for_tasks(struct se_cmd *, int, int);
-
static inline u32 transport_get_sectors_6(
unsigned char *cdb,
struct se_cmd *cmd,
@@ -2752,13 +2403,16 @@ out:
static int transport_get_sense_data(struct se_cmd *cmd)
{
unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
- struct se_device *dev;
+ struct se_device *dev = cmd->se_dev;
struct se_task *task = NULL, *task_tmp;
unsigned long flags;
u32 offset = 0;
WARN_ON(!cmd->se_lun);
+ if (!dev)
+ return 0;
+
spin_lock_irqsave(&cmd->t_state_lock, flags);
if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -2767,14 +2421,9 @@ static int transport_get_sense_data(struct se_cmd *cmd)
list_for_each_entry_safe(task, task_tmp,
&cmd->t_task_list, t_list) {
-
if (!task->task_sense)
continue;
- dev = task->se_dev;
- if (!dev)
- continue;
-
if (!dev->transport->get_sense_buffer) {
pr_err("dev->transport->get_sense_buffer"
" is NULL\n");
@@ -2783,9 +2432,9 @@ static int transport_get_sense_data(struct se_cmd *cmd)
sense_buffer = dev->transport->get_sense_buffer(task);
if (!sense_buffer) {
- pr_err("ITT[0x%08x]_TASK[%d]: Unable to locate"
+ pr_err("ITT[0x%08x]_TASK[%p]: Unable to locate"
" sense buffer for task with sense\n",
- cmd->se_tfo->get_task_tag(cmd), task->task_no);
+ cmd->se_tfo->get_task_tag(cmd), task);
continue;
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -2814,7 +2463,6 @@ static int transport_get_sense_data(struct se_cmd *cmd)
static int
transport_handle_reservation_conflict(struct se_cmd *cmd)
{
- cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
@@ -2915,8 +2563,6 @@ static int transport_generic_cmd_sequencer(
* Check for an existing UNIT ATTENTION condition
*/
if (core_scsi3_ua_check(cmd, cdb) < 0) {
- cmd->transport_wait_for_tasks =
- &transport_nop_wait_for_tasks;
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
return -EINVAL;
@@ -2926,7 +2572,6 @@ static int transport_generic_cmd_sequencer(
*/
ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq);
if (ret != 0) {
- cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
/*
* Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
* The ALUA additional sense code qualifier (ASCQ) is determined
@@ -2959,13 +2604,19 @@ static int transport_generic_cmd_sequencer(
*/
}
+ /*
+ * If we operate in passthrough mode we skip most CDB emulation and
+ * instead hand the commands down to the physical SCSI device.
+ */
+ passthrough =
+ (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV);
+
switch (cdb[0]) {
case READ_6:
sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_6;
cmd->t_task_lba = transport_lba_21(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2974,7 +2625,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_10;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2983,7 +2633,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_12;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2992,7 +2641,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_16;
cmd->t_task_lba = transport_lba_64(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -3001,7 +2649,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_6;
cmd->t_task_lba = transport_lba_21(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -3010,7 +2657,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_10;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->t_tasks_fua = (cdb[1] & 0x8);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
@@ -3020,7 +2666,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_12;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->t_tasks_fua = (cdb[1] & 0x8);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
@@ -3030,7 +2675,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_16;
cmd->t_task_lba = transport_lba_64(cdb);
cmd->t_tasks_fua = (cdb[1] & 0x8);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
@@ -3043,31 +2687,23 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_10;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
- passthrough = (dev->transport->transport_type ==
- TRANSPORT_PLUGIN_PHBA_PDEV);
+
/*
- * Skip the remaining assignments for TCM/PSCSI passthrough
+ * Do now allow BIDI commands for passthrough mode.
*/
if (passthrough)
- break;
+ goto out_unsupported_cdb;
+
/*
- * Setup BIDI XOR callback to be run during transport_generic_complete_ok()
+ * Setup BIDI XOR callback to be run after I/O completion.
*/
cmd->transport_complete_callback = &transport_xor_callback;
cmd->t_tasks_fua = (cdb[1] & 0x8);
break;
case VARIABLE_LENGTH_CMD:
service_action = get_unaligned_be16(&cdb[8]);
- /*
- * Determine if this is TCM/PSCSI device and we should disable
- * internal emulation for this CDB.
- */
- passthrough = (dev->transport->transport_type ==
- TRANSPORT_PLUGIN_PHBA_PDEV);
-
switch (service_action) {
case XDWRITEREAD_32:
sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
@@ -3078,19 +2714,18 @@ static int transport_generic_cmd_sequencer(
* Use WRITE_32 and READ_32 opcodes for the emulated
* XDWRITE_READ_32 logic.
*/
- cmd->transport_split_cdb = &split_cdb_XX_32;
cmd->t_task_lba = transport_lba_64_ext(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
/*
- * Skip the remaining assignments for TCM/PSCSI passthrough
+ * Do now allow BIDI commands for passthrough mode.
*/
if (passthrough)
- break;
+ goto out_unsupported_cdb;
/*
- * Setup BIDI XOR callback to be run during
- * transport_generic_complete_ok()
+ * Setup BIDI XOR callback to be run during after I/O
+ * completion.
*/
cmd->transport_complete_callback = &transport_xor_callback;
cmd->t_tasks_fua = (cdb[10] & 0x8);
@@ -3113,7 +2748,8 @@ static int transport_generic_cmd_sequencer(
if (target_check_write_same_discard(&cdb[10], dev) < 0)
goto out_invalid_cdb_field;
-
+ if (!passthrough)
+ cmd->execute_task = target_emulate_write_same;
break;
default:
pr_err("VARIABLE_LENGTH_CMD service action"
@@ -3127,12 +2763,10 @@ static int transport_generic_cmd_sequencer(
/*
* Check for emulated MI_REPORT_TARGET_PGS.
*/
- if (cdb[1] == MI_REPORT_TARGET_PGS) {
- cmd->transport_emulate_cdb =
- (su_dev->t10_alua.alua_type ==
- SPC3_ALUA_EMULATED) ?
- core_emulate_report_target_port_groups :
- NULL;
+ if (cdb[1] == MI_REPORT_TARGET_PGS &&
+ su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
+ cmd->execute_task =
+ target_emulate_report_target_port_groups;
}
size = (cdb[6] << 24) | (cdb[7] << 16) |
(cdb[8] << 8) | cdb[9];
@@ -3153,8 +2787,15 @@ static int transport_generic_cmd_sequencer(
case MODE_SENSE:
size = cdb[4];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_modesense;
break;
case MODE_SENSE_10:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_modesense;
+ break;
case GPCMD_READ_BUFFER_CAPACITY:
case GPCMD_SEND_OPC:
case LOG_SELECT:
@@ -3174,11 +2815,14 @@ static int transport_generic_cmd_sequencer(
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case PERSISTENT_RESERVE_IN:
+ if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
+ cmd->execute_task = target_scsi3_emulate_pr_in;
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
case PERSISTENT_RESERVE_OUT:
- cmd->transport_emulate_cdb =
- (su_dev->t10_pr.res_type ==
- SPC3_PERSISTENT_RESERVATIONS) ?
- core_scsi3_emulate_pr : NULL;
+ if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
+ cmd->execute_task = target_scsi3_emulate_pr_out;
size = (cdb[7] << 8) + cdb[8];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
@@ -3197,12 +2841,10 @@ static int transport_generic_cmd_sequencer(
*
* Check for emulated MO_SET_TARGET_PGS.
*/
- if (cdb[1] == MO_SET_TARGET_PGS) {
- cmd->transport_emulate_cdb =
- (su_dev->t10_alua.alua_type ==
- SPC3_ALUA_EMULATED) ?
- core_emulate_set_target_port_groups :
- NULL;
+ if (cdb[1] == MO_SET_TARGET_PGS &&
+ su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
+ cmd->execute_task =
+ target_emulate_set_target_port_groups;
}
size = (cdb[6] << 24) | (cdb[7] << 16) |
@@ -3222,6 +2864,8 @@ static int transport_generic_cmd_sequencer(
if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
cmd->sam_task_attr = MSG_HEAD_TAG;
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_inquiry;
break;
case READ_BUFFER:
size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
@@ -3230,6 +2874,8 @@ static int transport_generic_cmd_sequencer(
case READ_CAPACITY:
size = READ_CAP_LEN;
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_readcapacity;
break;
case READ_MEDIA_SERIAL_NUMBER:
case SECURITY_PROTOCOL_IN:
@@ -3238,6 +2884,21 @@ static int transport_generic_cmd_sequencer(
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case SERVICE_ACTION_IN:
+ switch (cmd->t_task_cdb[1] & 0x1f) {
+ case SAI_READ_CAPACITY_16:
+ if (!passthrough)
+ cmd->execute_task =
+ target_emulate_readcapacity_16;
+ break;
+ default:
+ if (passthrough)
+ break;
+
+ pr_err("Unsupported SA: 0x%02x\n",
+ cmd->t_task_cdb[1] & 0x1f);
+ goto out_unsupported_cdb;
+ }
+ /*FALLTHROUGH*/
case ACCESS_CONTROL_IN:
case ACCESS_CONTROL_OUT:
case EXTENDED_COPY:
@@ -3268,6 +2929,8 @@ static int transport_generic_cmd_sequencer(
case REQUEST_SENSE:
size = cdb[4];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_request_sense;
break;
case READ_ELEMENT_STATUS:
size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
@@ -3295,10 +2958,8 @@ static int transport_generic_cmd_sequencer(
* is running in SPC_PASSTHROUGH, and wants reservations
* emulation disabled.
*/
- cmd->transport_emulate_cdb =
- (su_dev->t10_pr.res_type !=
- SPC_PASSTHROUGH) ?
- core_scsi2_emulate_crh : NULL;
+ if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
+ cmd->execute_task = target_scsi2_reservation_reserve;
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
break;
case RELEASE:
@@ -3312,10 +2973,8 @@ static int transport_generic_cmd_sequencer(
else
size = cmd->data_length;
- cmd->transport_emulate_cdb =
- (su_dev->t10_pr.res_type !=
- SPC_PASSTHROUGH) ?
- core_scsi2_emulate_crh : NULL;
+ if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
+ cmd->execute_task = target_scsi2_reservation_release;
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
break;
case SYNCHRONIZE_CACHE:
@@ -3336,16 +2995,9 @@ static int transport_generic_cmd_sequencer(
size = transport_get_size(sectors, cdb, cmd);
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
- /*
- * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb()
- */
- if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+ if (passthrough)
break;
- /*
- * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation
- * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks()
- */
- cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC;
+
/*
* Check to ensure that LBA + Range does not exceed past end of
* device for IBLOCK and FILEIO ->do_sync_cache() backend calls
@@ -3354,10 +3006,13 @@ static int transport_generic_cmd_sequencer(
if (transport_cmd_get_valid_sectors(cmd) < 0)
goto out_invalid_cdb_field;
}
+ cmd->execute_task = target_emulate_synchronize_cache;
break;
case UNMAP:
size = get_unaligned_be16(&cdb[7]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_unmap;
break;
case WRITE_SAME_16:
sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
@@ -3376,6 +3031,8 @@ static int transport_generic_cmd_sequencer(
if (target_check_write_same_discard(&cdb[1], dev) < 0)
goto out_invalid_cdb_field;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_write_same;
break;
case WRITE_SAME:
sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
@@ -3397,26 +3054,31 @@ static int transport_generic_cmd_sequencer(
*/
if (target_check_write_same_discard(&cdb[1], dev) < 0)
goto out_invalid_cdb_field;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_write_same;
break;
case ALLOW_MEDIUM_REMOVAL:
- case GPCMD_CLOSE_TRACK:
case ERASE:
- case INITIALIZE_ELEMENT_STATUS:
- case GPCMD_LOAD_UNLOAD:
case REZERO_UNIT:
case SEEK_10:
- case GPCMD_SET_SPEED:
case SPACE:
case START_STOP:
case TEST_UNIT_READY:
case VERIFY:
case WRITE_FILEMARKS:
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ if (!passthrough)
+ cmd->execute_task = target_emulate_noop;
+ break;
+ case GPCMD_CLOSE_TRACK:
+ case INITIALIZE_ELEMENT_STATUS:
+ case GPCMD_LOAD_UNLOAD:
+ case GPCMD_SET_SPEED:
case MOVE_MEDIUM:
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
break;
case REPORT_LUNS:
- cmd->transport_emulate_cdb =
- transport_core_report_lun_response;
+ cmd->execute_task = target_report_luns;
size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
/*
* Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
@@ -3430,7 +3092,6 @@ static int transport_generic_cmd_sequencer(
pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
" 0x%02x, sending CHECK_CONDITION.\n",
cmd->se_tfo->get_fabric_name(), cdb[0]);
- cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
goto out_unsupported_cdb;
}
@@ -3469,6 +3130,11 @@ static int transport_generic_cmd_sequencer(
cmd->data_length = size;
}
+ /* reject any command that we don't have a handler for */
+ if (!(passthrough || cmd->execute_task ||
+ (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
+ goto out_unsupported_cdb;
+
/* Let's limit control cdbs to a page, for simplicity's sake. */
if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
size > PAGE_SIZE)
@@ -3488,8 +3154,7 @@ out_invalid_cdb_field:
}
/*
- * Called from transport_generic_complete_ok() and
- * transport_generic_request_failure() to determine which dormant/delayed
+ * Called from I/O completion to determine which dormant/delayed
* and ordered cmds need to have their tasks added to the execution queue.
*/
static void transport_complete_task_attr(struct se_cmd *cmd)
@@ -3557,12 +3222,18 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
}
-static int transport_complete_qf(struct se_cmd *cmd)
+static void transport_complete_qf(struct se_cmd *cmd)
{
int ret = 0;
- if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
- return cmd->se_tfo->queue_status(cmd);
+ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ transport_complete_task_attr(cmd);
+
+ if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
+ ret = cmd->se_tfo->queue_status(cmd);
+ if (ret)
+ goto out;
+ }
switch (cmd->data_direction) {
case DMA_FROM_DEVICE:
@@ -3572,7 +3243,7 @@ static int transport_complete_qf(struct se_cmd *cmd)
if (cmd->t_bidi_data_sg) {
ret = cmd->se_tfo->queue_data_in(cmd);
if (ret < 0)
- return ret;
+ break;
}
/* Fall through for DMA_TO_DEVICE */
case DMA_NONE:
@@ -3582,17 +3253,20 @@ static int transport_complete_qf(struct se_cmd *cmd)
break;
}
- return ret;
+out:
+ if (ret < 0) {
+ transport_handle_queue_full(cmd, cmd->se_dev);
+ return;
+ }
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
}
static void transport_handle_queue_full(
struct se_cmd *cmd,
- struct se_device *dev,
- int (*qf_callback)(struct se_cmd *))
+ struct se_device *dev)
{
spin_lock_irq(&dev->qf_cmd_lock);
- cmd->se_cmd_flags |= SCF_EMULATE_QUEUE_FULL;
- cmd->transport_qf_callback = qf_callback;
list_add_tail(&cmd->se_qf_node, &cmd->se_dev->qf_cmd_list);
atomic_inc(&dev->dev_qf_count);
smp_mb__after_atomic_inc();
@@ -3601,9 +3275,11 @@ static void transport_handle_queue_full(
schedule_work(&cmd->se_dev->qf_work_queue);
}
-static void transport_generic_complete_ok(struct se_cmd *cmd)
+static void target_complete_ok_work(struct work_struct *work)
{
+ struct se_cmd *cmd = container_of(work, struct se_cmd, work);
int reason = 0, ret;
+
/*
* Check if we need to move delayed/dormant tasks from cmds on the
* delayed execution list after a HEAD_OF_QUEUE or ORDERED Task
@@ -3618,14 +3294,6 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
if (atomic_read(&cmd->se_dev->dev_qf_count) != 0)
schedule_work(&cmd->se_dev->qf_work_queue);
- if (cmd->transport_qf_callback) {
- ret = cmd->transport_qf_callback(cmd);
- if (ret < 0)
- goto queue_full;
-
- cmd->transport_qf_callback = NULL;
- goto done;
- }
/*
* Check if we need to retrieve a sense buffer from
* the struct se_cmd in question.
@@ -3641,7 +3309,7 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
if (cmd->scsi_status) {
ret = transport_send_check_condition_and_sense(
cmd, reason, 1);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
transport_lun_remove_cmd(cmd);
@@ -3666,7 +3334,7 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
spin_unlock(&cmd->se_lun->lun_sep_lock);
ret = cmd->se_tfo->queue_data_in(cmd);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
break;
case DMA_TO_DEVICE:
@@ -3687,21 +3355,20 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
}
spin_unlock(&cmd->se_lun->lun_sep_lock);
ret = cmd->se_tfo->queue_data_in(cmd);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
break;
}
/* Fall through for DMA_TO_DEVICE */
case DMA_NONE:
ret = cmd->se_tfo->queue_status(cmd);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
break;
default:
break;
}
-done:
transport_lun_remove_cmd(cmd);
transport_cmd_check_stop_to_fabric(cmd);
return;
@@ -3709,34 +3376,35 @@ done:
queue_full:
pr_debug("Handling complete_ok QUEUE_FULL: se_cmd: %p,"
" data_direction: %d\n", cmd, cmd->data_direction);
- transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf);
+ cmd->t_state = TRANSPORT_COMPLETE_QF_OK;
+ transport_handle_queue_full(cmd, cmd->se_dev);
}
static void transport_free_dev_tasks(struct se_cmd *cmd)
{
struct se_task *task, *task_tmp;
unsigned long flags;
+ LIST_HEAD(dispose_list);
spin_lock_irqsave(&cmd->t_state_lock, flags);
list_for_each_entry_safe(task, task_tmp,
&cmd->t_task_list, t_list) {
- if (atomic_read(&task->task_active))
- continue;
+ if (!(task->task_flags & TF_ACTIVE))
+ list_move_tail(&task->t_list, &dispose_list);
+ }
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
+ while (!list_empty(&dispose_list)) {
+ task = list_first_entry(&dispose_list, struct se_task, t_list);
- kfree(task->task_sg_bidi);
- kfree(task->task_sg);
+ if (task->task_sg != cmd->t_data_sg &&
+ task->task_sg != cmd->t_bidi_data_sg)
+ kfree(task->task_sg);
list_del(&task->t_list);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (task->se_dev)
- task->se_dev->transport->free_task(task);
- else
- pr_err("task[%u] - task->se_dev is NULL\n",
- task->task_no);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
+ cmd->se_dev->transport->free_task(task);
}
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
static inline void transport_free_sgl(struct scatterlist *sgl, int nents)
@@ -3764,89 +3432,43 @@ static inline void transport_free_pages(struct se_cmd *cmd)
cmd->t_bidi_data_nents = 0;
}
-static inline void transport_release_tasks(struct se_cmd *cmd)
-{
- transport_free_dev_tasks(cmd);
-}
-
-static inline int transport_dec_and_check(struct se_cmd *cmd)
+/**
+ * transport_put_cmd - release a reference to a command
+ * @cmd: command to release
+ *
+ * This routine releases our reference to the command and frees it if possible.
+ */
+static void transport_put_cmd(struct se_cmd *cmd)
{
unsigned long flags;
+ int free_tasks = 0;
spin_lock_irqsave(&cmd->t_state_lock, flags);
if (atomic_read(&cmd->t_fe_count)) {
- if (!atomic_dec_and_test(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- return 1;
- }
+ if (!atomic_dec_and_test(&cmd->t_fe_count))
+ goto out_busy;
}
if (atomic_read(&cmd->t_se_count)) {
- if (!atomic_dec_and_test(&cmd->t_se_count)) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- return 1;
- }
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- return 0;
-}
-
-static void transport_release_fe_cmd(struct se_cmd *cmd)
-{
- unsigned long flags;
-
- if (transport_dec_and_check(cmd))
- return;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (!atomic_read(&cmd->transport_dev_active)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- goto free_pages;
+ if (!atomic_dec_and_test(&cmd->t_se_count))
+ goto out_busy;
}
- atomic_set(&cmd->transport_dev_active, 0);
- transport_all_task_dev_remove_state(cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_release_tasks(cmd);
-free_pages:
- transport_free_pages(cmd);
- transport_free_se_cmd(cmd);
- cmd->se_tfo->release_cmd(cmd);
-}
-
-static int
-transport_generic_remove(struct se_cmd *cmd, int session_reinstatement)
-{
- unsigned long flags;
-
- if (transport_dec_and_check(cmd)) {
- if (session_reinstatement) {
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- transport_all_task_dev_remove_state(cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- }
- return 1;
- }
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (!atomic_read(&cmd->transport_dev_active)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- goto free_pages;
+ if (atomic_read(&cmd->transport_dev_active)) {
+ atomic_set(&cmd->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ free_tasks = 1;
}
- atomic_set(&cmd->transport_dev_active, 0);
- transport_all_task_dev_remove_state(cmd);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_release_tasks(cmd);
+ if (free_tasks != 0)
+ transport_free_dev_tasks(cmd);
-free_pages:
transport_free_pages(cmd);
transport_release_cmd(cmd);
- return 0;
+ return;
+out_busy:
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
/*
@@ -3888,62 +3510,6 @@ int transport_generic_map_mem_to_cmd(
}
EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);
-static int transport_new_cmd_obj(struct se_cmd *cmd)
-{
- struct se_device *dev = cmd->se_dev;
- int set_counts = 1, rc, task_cdbs;
-
- /*
- * Setup any BIDI READ tasks and memory from
- * cmd->t_mem_bidi_list so the READ struct se_tasks
- * are queued first for the non pSCSI passthrough case.
- */
- if (cmd->t_bidi_data_sg &&
- (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV)) {
- rc = transport_allocate_tasks(cmd,
- cmd->t_task_lba,
- DMA_FROM_DEVICE,
- cmd->t_bidi_data_sg,
- cmd->t_bidi_data_nents);
- if (rc <= 0) {
- cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
- cmd->scsi_sense_reason =
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return -EINVAL;
- }
- atomic_inc(&cmd->t_fe_count);
- atomic_inc(&cmd->t_se_count);
- set_counts = 0;
- }
- /*
- * Setup the tasks and memory from cmd->t_mem_list
- * Note for BIDI transfers this will contain the WRITE payload
- */
- task_cdbs = transport_allocate_tasks(cmd,
- cmd->t_task_lba,
- cmd->data_direction,
- cmd->t_data_sg,
- cmd->t_data_nents);
- if (task_cdbs <= 0) {
- cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
- cmd->scsi_sense_reason =
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return -EINVAL;
- }
-
- if (set_counts) {
- atomic_inc(&cmd->t_fe_count);
- atomic_inc(&cmd->t_se_count);
- }
-
- cmd->t_task_list_num = task_cdbs;
-
- atomic_set(&cmd->t_task_cdbs_left, task_cdbs);
- atomic_set(&cmd->t_task_cdbs_ex_left, task_cdbs);
- atomic_set(&cmd->t_task_cdbs_timeout_left, task_cdbs);
- return 0;
-}
-
void *transport_kmap_first_data_page(struct se_cmd *cmd)
{
struct scatterlist *sg = cmd->t_data_sg;
@@ -4054,15 +3620,13 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
/*
* For the padded tasks, use the extra SGL vector allocated
* in transport_allocate_data_tasks() for the sg_prev_nents
- * offset into sg_chain() above.. The last task of a
- * multi-task list, or a single task will not have
- * task->task_sg_padded set..
+ * offset into sg_chain() above.
+ *
+ * We do not need the padding for the last task (or a single
+ * task), but in that case we will never use the sg_prev_nents
+ * value below which would be incorrect.
*/
- if (task->task_padded_sg)
- sg_prev_nents = (task->task_sg_nents + 1);
- else
- sg_prev_nents = task->task_sg_nents;
-
+ sg_prev_nents = (task->task_sg_nents + 1);
sg_prev = task->task_sg;
}
/*
@@ -4092,30 +3656,60 @@ EXPORT_SYMBOL(transport_do_task_sg_chain);
/*
* Break up cmd into chunks transport can handle
*/
-static int transport_allocate_data_tasks(
- struct se_cmd *cmd,
- unsigned long long lba,
+static int
+transport_allocate_data_tasks(struct se_cmd *cmd,
enum dma_data_direction data_direction,
- struct scatterlist *sgl,
- unsigned int sgl_nents)
+ struct scatterlist *cmd_sg, unsigned int sgl_nents)
{
- unsigned char *cdb = NULL;
- struct se_task *task;
struct se_device *dev = cmd->se_dev;
- unsigned long flags;
- int task_count, i, ret;
- sector_t sectors, dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
- u32 sector_size = dev->se_sub_dev->se_dev_attrib.block_size;
- struct scatterlist *sg;
- struct scatterlist *cmd_sg;
+ int task_count, i;
+ unsigned long long lba;
+ sector_t sectors, dev_max_sectors;
+ u32 sector_size;
+
+ if (transport_cmd_get_valid_sectors(cmd) < 0)
+ return -EINVAL;
+
+ dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
+ sector_size = dev->se_sub_dev->se_dev_attrib.block_size;
WARN_ON(cmd->data_length % sector_size);
+
+ lba = cmd->t_task_lba;
sectors = DIV_ROUND_UP(cmd->data_length, sector_size);
task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors);
-
- cmd_sg = sgl;
+
+ /*
+ * If we need just a single task reuse the SG list in the command
+ * and avoid a lot of work.
+ */
+ if (task_count == 1) {
+ struct se_task *task;
+ unsigned long flags;
+
+ task = transport_generic_get_task(cmd, data_direction);
+ if (!task)
+ return -ENOMEM;
+
+ task->task_sg = cmd_sg;
+ task->task_sg_nents = sgl_nents;
+
+ task->task_lba = lba;
+ task->task_sectors = sectors;
+ task->task_size = task->task_sectors * sector_size;
+
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ list_add_tail(&task->t_list, &cmd->t_task_list);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
+ return task_count;
+ }
+
for (i = 0; i < task_count; i++) {
+ struct se_task *task;
unsigned int task_size, task_sg_nents_padded;
+ struct scatterlist *sg;
+ unsigned long flags;
int count;
task = transport_generic_get_task(cmd, data_direction);
@@ -4126,14 +3720,6 @@ static int transport_allocate_data_tasks(
task->task_sectors = min(sectors, dev_max_sectors);
task->task_size = task->task_sectors * sector_size;
- cdb = dev->transport->get_cdb(task);
- BUG_ON(!cdb);
-
- memcpy(cdb, cmd->t_task_cdb,
- scsi_command_size(cmd->t_task_cdb));
-
- /* Update new cdb with updated lba/sectors */
- cmd->transport_split_cdb(task->task_lba, task->task_sectors, cdb);
/*
* This now assumes that passed sg_ents are in PAGE_SIZE chunks
* in order to calculate the number per task SGL entries
@@ -4149,7 +3735,6 @@ static int transport_allocate_data_tasks(
*/
if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) {
task_sg_nents_padded = (task->task_sg_nents + 1);
- task->task_padded_sg = 1;
} else
task_sg_nents_padded = task->task_sg_nents;
@@ -4181,20 +3766,6 @@ static int transport_allocate_data_tasks(
list_add_tail(&task->t_list, &cmd->t_task_list);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
- /*
- * Now perform the memory map of task->task_sg[] into backend
- * subsystem memory..
- */
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (atomic_read(&task->task_sent))
- continue;
- if (!dev->transport->map_data_SG)
- continue;
-
- ret = dev->transport->map_data_SG(task);
- if (ret < 0)
- return 0;
- }
return task_count;
}
@@ -4202,30 +3773,14 @@ static int transport_allocate_data_tasks(
static int
transport_allocate_control_task(struct se_cmd *cmd)
{
- struct se_device *dev = cmd->se_dev;
- unsigned char *cdb;
struct se_task *task;
unsigned long flags;
- int ret = 0;
task = transport_generic_get_task(cmd, cmd->data_direction);
if (!task)
return -ENOMEM;
- cdb = dev->transport->get_cdb(task);
- BUG_ON(!cdb);
- memcpy(cdb, cmd->t_task_cdb,
- scsi_command_size(cmd->t_task_cdb));
-
- task->task_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
- GFP_KERNEL);
- if (!task->task_sg) {
- cmd->se_dev->transport->free_task(task);
- return -ENOMEM;
- }
-
- memcpy(task->task_sg, cmd->t_data_sg,
- sizeof(struct scatterlist) * cmd->t_data_nents);
+ task->task_sg = cmd->t_data_sg;
task->task_size = cmd->data_length;
task->task_sg_nents = cmd->t_data_nents;
@@ -4233,53 +3788,20 @@ transport_allocate_control_task(struct se_cmd *cmd)
list_add_tail(&task->t_list, &cmd->t_task_list);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) {
- if (dev->transport->map_control_SG)
- ret = dev->transport->map_control_SG(task);
- } else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
- if (dev->transport->cdb_none)
- ret = dev->transport->cdb_none(task);
- } else {
- pr_err("target: Unknown control cmd type!\n");
- BUG();
- }
-
/* Success! Return number of tasks allocated */
- if (ret == 0)
- return 1;
- return ret;
-}
-
-static u32 transport_allocate_tasks(
- struct se_cmd *cmd,
- unsigned long long lba,
- enum dma_data_direction data_direction,
- struct scatterlist *sgl,
- unsigned int sgl_nents)
-{
- if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
- if (transport_cmd_get_valid_sectors(cmd) < 0)
- return -EINVAL;
-
- return transport_allocate_data_tasks(cmd, lba, data_direction,
- sgl, sgl_nents);
- } else
- return transport_allocate_control_task(cmd);
-
+ return 1;
}
-
-/* transport_generic_new_cmd(): Called from transport_processing_thread()
- *
- * Allocate storage transport resources from a set of values predefined
- * by transport_generic_cmd_sequencer() from the iSCSI Target RX process.
- * Any non zero return here is treated as an "out of resource' op here.
+/*
+ * Allocate any required ressources to execute the command, and either place
+ * it on the execution queue if possible. For writes we might not have the
+ * payload yet, thus notify the fabric via a call to ->write_pending instead.
*/
- /*
- * Generate struct se_task(s) and/or their payloads for this CDB.
- */
int transport_generic_new_cmd(struct se_cmd *cmd)
{
+ struct se_device *dev = cmd->se_dev;
+ int task_cdbs, task_cdbs_bidi = 0;
+ int set_counts = 1;
int ret = 0;
/*
@@ -4293,16 +3815,45 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
if (ret < 0)
return ret;
}
+
/*
- * Call transport_new_cmd_obj() to invoke transport_allocate_tasks() for
- * control or data CDB types, and perform the map to backend subsystem
- * code from SGL memory allocated here by transport_generic_get_mem(), or
- * via pre-existing SGL memory setup explictly by fabric module code with
- * transport_generic_map_mem_to_cmd().
+ * For BIDI command set up the read tasks first.
*/
- ret = transport_new_cmd_obj(cmd);
- if (ret < 0)
- return ret;
+ if (cmd->t_bidi_data_sg &&
+ dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
+ BUG_ON(!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB));
+
+ task_cdbs_bidi = transport_allocate_data_tasks(cmd,
+ DMA_FROM_DEVICE, cmd->t_bidi_data_sg,
+ cmd->t_bidi_data_nents);
+ if (task_cdbs_bidi <= 0)
+ goto out_fail;
+
+ atomic_inc(&cmd->t_fe_count);
+ atomic_inc(&cmd->t_se_count);
+ set_counts = 0;
+ }
+
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ task_cdbs = transport_allocate_data_tasks(cmd,
+ cmd->data_direction, cmd->t_data_sg,
+ cmd->t_data_nents);
+ } else {
+ task_cdbs = transport_allocate_control_task(cmd);
+ }
+
+ if (task_cdbs <= 0)
+ goto out_fail;
+
+ if (set_counts) {
+ atomic_inc(&cmd->t_fe_count);
+ atomic_inc(&cmd->t_se_count);
+ }
+
+ cmd->t_task_list_num = (task_cdbs + task_cdbs_bidi);
+ atomic_set(&cmd->t_task_cdbs_left, cmd->t_task_list_num);
+ atomic_set(&cmd->t_task_cdbs_ex_left, cmd->t_task_list_num);
+
/*
* For WRITEs, let the fabric know its buffer is ready..
* This WRITE struct se_cmd (and all of its associated struct se_task's)
@@ -4320,6 +3871,11 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
*/
transport_execute_tasks(cmd);
return 0;
+
+out_fail:
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return -EINVAL;
}
EXPORT_SYMBOL(transport_generic_new_cmd);
@@ -4333,15 +3889,18 @@ void transport_generic_process_write(struct se_cmd *cmd)
}
EXPORT_SYMBOL(transport_generic_process_write);
-static int transport_write_pending_qf(struct se_cmd *cmd)
+static void transport_write_pending_qf(struct se_cmd *cmd)
{
- return cmd->se_tfo->write_pending(cmd);
+ int ret;
+
+ ret = cmd->se_tfo->write_pending(cmd);
+ if (ret == -EAGAIN || ret == -ENOMEM) {
+ pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n",
+ cmd);
+ transport_handle_queue_full(cmd, cmd->se_dev);
+ }
}
-/* transport_generic_write_pending():
- *
- *
- */
static int transport_generic_write_pending(struct se_cmd *cmd)
{
unsigned long flags;
@@ -4351,17 +3910,6 @@ static int transport_generic_write_pending(struct se_cmd *cmd)
cmd->t_state = TRANSPORT_WRITE_PENDING;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (cmd->transport_qf_callback) {
- ret = cmd->transport_qf_callback(cmd);
- if (ret == -EAGAIN)
- goto queue_full;
- else if (ret < 0)
- return ret;
-
- cmd->transport_qf_callback = NULL;
- return 0;
- }
-
/*
* Clear the se_cmd for WRITE_PENDING status in order to set
* cmd->t_transport_active=0 so that transport_generic_handle_data
@@ -4376,7 +3924,7 @@ static int transport_generic_write_pending(struct se_cmd *cmd)
* frontend know that WRITE buffers are ready.
*/
ret = cmd->se_tfo->write_pending(cmd);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
else if (ret < 0)
return ret;
@@ -4386,60 +3934,167 @@ static int transport_generic_write_pending(struct se_cmd *cmd)
queue_full:
pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd);
cmd->t_state = TRANSPORT_COMPLETE_QF_WP;
- transport_handle_queue_full(cmd, cmd->se_dev,
- transport_write_pending_qf);
- return ret;
+ transport_handle_queue_full(cmd, cmd->se_dev);
+ return 0;
}
+/**
+ * transport_release_cmd - free a command
+ * @cmd: command to free
+ *
+ * This routine unconditionally frees a command, and reference counting
+ * or list removal must be done in the caller.
+ */
void transport_release_cmd(struct se_cmd *cmd)
{
BUG_ON(!cmd->se_tfo);
- transport_free_se_cmd(cmd);
+ if (cmd->se_tmr_req)
+ core_tmr_release_req(cmd->se_tmr_req);
+ if (cmd->t_task_cdb != cmd->__t_task_cdb)
+ kfree(cmd->t_task_cdb);
+ /*
+ * Check if target_wait_for_sess_cmds() is expecting to
+ * release se_cmd directly here..
+ */
+ if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd)
+ if (cmd->se_tfo->check_release_cmd(cmd) != 0)
+ return;
+
cmd->se_tfo->release_cmd(cmd);
}
EXPORT_SYMBOL(transport_release_cmd);
-/* transport_generic_free_cmd():
- *
- * Called from processing frontend to release storage engine resources
- */
-void transport_generic_free_cmd(
- struct se_cmd *cmd,
- int wait_for_tasks,
- int session_reinstatement)
+void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
{
- if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD))
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
+ if (wait_for_tasks && cmd->se_tmr_req)
+ transport_wait_for_tasks(cmd);
+
transport_release_cmd(cmd);
- else {
+ } else {
+ if (wait_for_tasks)
+ transport_wait_for_tasks(cmd);
+
core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd);
- if (cmd->se_lun) {
-#if 0
- pr_debug("cmd: %p ITT: 0x%08x contains"
- " cmd->se_lun\n", cmd,
- cmd->se_tfo->get_task_tag(cmd));
-#endif
+ if (cmd->se_lun)
transport_lun_remove_cmd(cmd);
- }
-
- if (wait_for_tasks && cmd->transport_wait_for_tasks)
- cmd->transport_wait_for_tasks(cmd, 0, 0);
transport_free_dev_tasks(cmd);
- transport_generic_remove(cmd, session_reinstatement);
+ transport_put_cmd(cmd);
}
}
EXPORT_SYMBOL(transport_generic_free_cmd);
-static void transport_nop_wait_for_tasks(
- struct se_cmd *cmd,
- int remove_cmd,
- int session_reinstatement)
+/* target_get_sess_cmd - Add command to active ->sess_cmd_list
+ * @se_sess: session to reference
+ * @se_cmd: command descriptor to add
+ */
+void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
{
- return;
+ unsigned long flags;
+
+ spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+ list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
+ se_cmd->check_release = 1;
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
}
+EXPORT_SYMBOL(target_get_sess_cmd);
+
+/* target_put_sess_cmd - Check for active I/O shutdown or list delete
+ * @se_sess: session to reference
+ * @se_cmd: command descriptor to drop
+ */
+int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+ if (list_empty(&se_cmd->se_cmd_list)) {
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ WARN_ON(1);
+ return 0;
+ }
+
+ if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ complete(&se_cmd->cmd_wait_comp);
+ return 1;
+ }
+ list_del(&se_cmd->se_cmd_list);
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(target_put_sess_cmd);
+
+/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list
+ * @se_sess: session to split
+ */
+void target_splice_sess_cmd_list(struct se_session *se_sess)
+{
+ struct se_cmd *se_cmd;
+ unsigned long flags;
+
+ WARN_ON(!list_empty(&se_sess->sess_wait_list));
+ INIT_LIST_HEAD(&se_sess->sess_wait_list);
+
+ spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+ se_sess->sess_tearing_down = 1;
+
+ list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
+
+ list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
+ se_cmd->cmd_wait_set = 1;
+
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+}
+EXPORT_SYMBOL(target_splice_sess_cmd_list);
+
+/* target_wait_for_sess_cmds - Wait for outstanding descriptors
+ * @se_sess: session to wait for active I/O
+ * @wait_for_tasks: Make extra transport_wait_for_tasks call
+ */
+void target_wait_for_sess_cmds(
+ struct se_session *se_sess,
+ int wait_for_tasks)
+{
+ struct se_cmd *se_cmd, *tmp_cmd;
+ bool rc = false;
+
+ list_for_each_entry_safe(se_cmd, tmp_cmd,
+ &se_sess->sess_wait_list, se_cmd_list) {
+ list_del(&se_cmd->se_cmd_list);
+
+ pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
+ " %d\n", se_cmd, se_cmd->t_state,
+ se_cmd->se_tfo->get_cmd_state(se_cmd));
+
+ if (wait_for_tasks) {
+ pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d,"
+ " fabric state: %d\n", se_cmd, se_cmd->t_state,
+ se_cmd->se_tfo->get_cmd_state(se_cmd));
+
+ rc = transport_wait_for_tasks(se_cmd);
+
+ pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d,"
+ " fabric state: %d\n", se_cmd, se_cmd->t_state,
+ se_cmd->se_tfo->get_cmd_state(se_cmd));
+ }
+
+ if (!rc) {
+ wait_for_completion(&se_cmd->cmd_wait_comp);
+ pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
+ " fabric state: %d\n", se_cmd, se_cmd->t_state,
+ se_cmd->se_tfo->get_cmd_state(se_cmd));
+ }
+
+ se_cmd->se_tfo->release_cmd(se_cmd);
+ }
+}
+EXPORT_SYMBOL(target_wait_for_sess_cmds);
/* transport_lun_wait_for_tasks():
*
@@ -4479,7 +4134,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
pr_debug("ConfigFS: ITT[0x%08x] - stopped cmd....\n",
cmd->se_tfo->get_task_tag(cmd));
}
- transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj);
+ transport_remove_cmd_from_queue(cmd);
return 0;
}
@@ -4610,22 +4265,30 @@ int transport_clear_lun_from_sessions(struct se_lun *lun)
return 0;
}
-/* transport_generic_wait_for_tasks():
+/**
+ * transport_wait_for_tasks - wait for completion to occur
+ * @cmd: command to wait
*
- * Called from frontend or passthrough context to wait for storage engine
- * to pause and/or release frontend generated struct se_cmd.
+ * Called from frontend fabric context to wait for storage engine
+ * to pause and/or release frontend generated struct se_cmd.
*/
-static void transport_generic_wait_for_tasks(
- struct se_cmd *cmd,
- int remove_cmd,
- int session_reinstatement)
+bool transport_wait_for_tasks(struct se_cmd *cmd)
{
unsigned long flags;
- if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req))
- return;
-
spin_lock_irqsave(&cmd->t_state_lock, flags);
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return false;
+ }
+ /*
+ * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE
+ * has been set in transport_set_supported_SAM_opcode().
+ */
+ if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return false;
+ }
/*
* If we are already stopped due to an external event (ie: LUN shutdown)
* sleep until the connection can have the passed struct se_cmd back.
@@ -4665,16 +4328,17 @@ static void transport_generic_wait_for_tasks(
atomic_set(&cmd->transport_lun_stop, 0);
}
if (!atomic_read(&cmd->t_transport_active) ||
- atomic_read(&cmd->t_transport_aborted))
- goto remove;
+ atomic_read(&cmd->t_transport_aborted)) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return false;
+ }
atomic_set(&cmd->t_transport_stop, 1);
pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x"
- " i_state: %d, t_state/def_t_state: %d/%d, t_transport_stop"
- " = TRUE\n", cmd, cmd->se_tfo->get_task_tag(cmd),
- cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
- cmd->deferred_t_state);
+ " i_state: %d, t_state: %d, t_transport_stop = TRUE\n",
+ cmd, cmd->se_tfo->get_task_tag(cmd),
+ cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -4689,13 +4353,12 @@ static void transport_generic_wait_for_tasks(
pr_debug("wait_for_tasks: Stopped wait_for_compltion("
"&cmd->t_transport_stop_comp) for ITT: 0x%08x\n",
cmd->se_tfo->get_task_tag(cmd));
-remove:
+
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (!remove_cmd)
- return;
- transport_generic_free_cmd(cmd, 0, session_reinstatement);
+ return true;
}
+EXPORT_SYMBOL(transport_wait_for_tasks);
static int transport_get_sense_codes(
struct se_cmd *cmd,
@@ -4920,6 +4583,15 @@ EXPORT_SYMBOL(transport_check_aborted_status);
void transport_send_task_abort(struct se_cmd *cmd)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
/*
* If there are still expected incoming fabric WRITEs, we wait
* until until they have completed before sending a TASK_ABORTED
@@ -4984,184 +4656,10 @@ int transport_generic_do_tmr(struct se_cmd *cmd)
cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
cmd->se_tfo->queue_tm_rsp(cmd);
- transport_cmd_check_stop(cmd, 2, 0);
+ transport_cmd_check_stop_to_fabric(cmd);
return 0;
}
-/*
- * Called with spin_lock_irq(&dev->execute_task_lock); held
- *
- */
-static struct se_task *
-transport_get_task_from_state_list(struct se_device *dev)
-{
- struct se_task *task;
-
- if (list_empty(&dev->state_task_list))
- return NULL;
-
- list_for_each_entry(task, &dev->state_task_list, t_state_list)
- break;
-
- list_del(&task->t_state_list);
- atomic_set(&task->task_state_active, 0);
-
- return task;
-}
-
-static void transport_processing_shutdown(struct se_device *dev)
-{
- struct se_cmd *cmd;
- struct se_task *task;
- unsigned long flags;
- /*
- * Empty the struct se_device's struct se_task state list.
- */
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- while ((task = transport_get_task_from_state_list(dev))) {
- if (!task->task_se_cmd) {
- pr_err("task->task_se_cmd is NULL!\n");
- continue;
- }
- cmd = task->task_se_cmd;
-
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
-
- pr_debug("PT: cmd: %p task: %p ITT: 0x%08x,"
- " i_state: %d, t_state/def_t_state:"
- " %d/%d cdb: 0x%02x\n", cmd, task,
- cmd->se_tfo->get_task_tag(cmd),
- cmd->se_tfo->get_cmd_state(cmd),
- cmd->t_state, cmd->deferred_t_state,
- cmd->t_task_cdb[0]);
- pr_debug("PT: ITT[0x%08x] - t_tasks: %d t_task_cdbs_left:"
- " %d t_task_cdbs_sent: %d -- t_transport_active: %d"
- " t_transport_stop: %d t_transport_sent: %d\n",
- cmd->se_tfo->get_task_tag(cmd),
- cmd->t_task_list_num,
- atomic_read(&cmd->t_task_cdbs_left),
- atomic_read(&cmd->t_task_cdbs_sent),
- atomic_read(&cmd->t_transport_active),
- atomic_read(&cmd->t_transport_stop),
- atomic_read(&cmd->t_transport_sent));
-
- if (atomic_read(&task->task_active)) {
- atomic_set(&task->task_stop, 1);
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- pr_debug("Waiting for task: %p to shutdown for dev:"
- " %p\n", task, dev);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("Completed task: %p shutdown for dev: %p\n",
- task, dev);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_dec(&cmd->t_task_cdbs_left);
-
- atomic_set(&task->task_active, 0);
- atomic_set(&task->task_stop, 0);
- } else {
- if (atomic_read(&task->task_execute_queue) != 0)
- transport_remove_task_from_execute_queue(task, dev);
- }
- __transport_stop_task_timer(task, &flags);
-
- if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- pr_debug("Skipping task: %p, dev: %p for"
- " t_task_cdbs_ex_left: %d\n", task, dev,
- atomic_read(&cmd->t_task_cdbs_ex_left));
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- continue;
- }
-
- if (atomic_read(&cmd->t_transport_active)) {
- pr_debug("got t_transport_active = 1 for task: %p, dev:"
- " %p\n", task, dev);
-
- if (atomic_read(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
- transport_send_check_condition_and_sense(
- cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE,
- 0);
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
-
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop(cmd, 1, 0);
- } else {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
-
- transport_lun_remove_cmd(cmd);
-
- if (transport_cmd_check_stop(cmd, 1, 0))
- transport_generic_remove(cmd, 0);
- }
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- continue;
- }
- pr_debug("Got t_transport_active = 0 for task: %p, dev: %p\n",
- task, dev);
-
- if (atomic_read(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
- transport_send_check_condition_and_sense(cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
-
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop(cmd, 1, 0);
- } else {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
- transport_lun_remove_cmd(cmd);
-
- if (transport_cmd_check_stop(cmd, 1, 0))
- transport_generic_remove(cmd, 0);
- }
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- }
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
- /*
- * Empty the struct se_device's struct se_cmd list.
- */
- while ((cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj))) {
-
- pr_debug("From Device Queue: cmd: %p t_state: %d\n",
- cmd, cmd->t_state);
-
- if (atomic_read(&cmd->t_fe_count)) {
- transport_send_check_condition_and_sense(cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
-
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop(cmd, 1, 0);
- } else {
- transport_lun_remove_cmd(cmd);
- if (transport_cmd_check_stop(cmd, 1, 0))
- transport_generic_remove(cmd, 0);
- }
- }
-}
-
/* transport_processing_thread():
*
*
@@ -5181,14 +4679,6 @@ static int transport_processing_thread(void *param)
if (ret < 0)
goto out;
- spin_lock_irq(&dev->dev_status_lock);
- if (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) {
- spin_unlock_irq(&dev->dev_status_lock);
- transport_processing_shutdown(dev);
- continue;
- }
- spin_unlock_irq(&dev->dev_status_lock);
-
get_cmd:
__transport_execute_tasks(dev);
@@ -5197,6 +4687,9 @@ get_cmd:
continue;
switch (cmd->t_state) {
+ case TRANSPORT_NEW_CMD:
+ BUG();
+ break;
case TRANSPORT_NEW_CMD_MAP:
if (!cmd->se_tfo->new_cmd_map) {
pr_err("cmd->se_tfo->new_cmd_map is"
@@ -5206,19 +4699,15 @@ get_cmd:
ret = cmd->se_tfo->new_cmd_map(cmd);
if (ret < 0) {
cmd->transport_error_status = ret;
- transport_generic_request_failure(cmd, NULL,
+ transport_generic_request_failure(cmd,
0, (cmd->data_direction !=
DMA_TO_DEVICE));
break;
}
- /* Fall through */
- case TRANSPORT_NEW_CMD:
ret = transport_generic_new_cmd(cmd);
- if (ret == -EAGAIN)
- break;
- else if (ret < 0) {
+ if (ret < 0) {
cmd->transport_error_status = ret;
- transport_generic_request_failure(cmd, NULL,
+ transport_generic_request_failure(cmd,
0, (cmd->data_direction !=
DMA_TO_DEVICE));
}
@@ -5226,33 +4715,19 @@ get_cmd:
case TRANSPORT_PROCESS_WRITE:
transport_generic_process_write(cmd);
break;
- case TRANSPORT_COMPLETE_OK:
- transport_stop_all_task_timers(cmd);
- transport_generic_complete_ok(cmd);
- break;
- case TRANSPORT_REMOVE:
- transport_generic_remove(cmd, 0);
- break;
- case TRANSPORT_FREE_CMD_INTR:
- transport_generic_free_cmd(cmd, 0, 0);
- break;
case TRANSPORT_PROCESS_TMR:
transport_generic_do_tmr(cmd);
break;
- case TRANSPORT_COMPLETE_FAILURE:
- transport_generic_request_failure(cmd, NULL, 1, 1);
- break;
- case TRANSPORT_COMPLETE_TIMEOUT:
- transport_stop_all_task_timers(cmd);
- transport_generic_request_timeout(cmd);
- break;
case TRANSPORT_COMPLETE_QF_WP:
- transport_generic_write_pending(cmd);
+ transport_write_pending_qf(cmd);
+ break;
+ case TRANSPORT_COMPLETE_QF_OK:
+ transport_complete_qf(cmd);
break;
default:
- pr_err("Unknown t_state: %d deferred_t_state:"
- " %d for ITT: 0x%08x i_state: %d on SE LUN:"
- " %u\n", cmd->t_state, cmd->deferred_t_state,
+ pr_err("Unknown t_state: %d for ITT: 0x%08x "
+ "i_state: %d on SE LUN: %u\n",
+ cmd->t_state,
cmd->se_tfo->get_task_tag(cmd),
cmd->se_tfo->get_cmd_state(cmd),
cmd->se_lun->unpacked_lun);
@@ -5263,7 +4738,8 @@ get_cmd:
}
out:
- transport_release_all_cmds(dev);
+ WARN_ON(!list_empty(&dev->state_task_list));
+ WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list));
dev->process_thread = NULL;
return 0;
}
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c
index 31e3c652527e..50a480db7a66 100644
--- a/drivers/target/target_core_ua.c
+++ b/drivers/target/target_core_ua.c
@@ -24,7 +24,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <scsi/scsi.h>
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index 3749d8b4b423..e05c55100ec6 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -156,7 +156,7 @@ int ft_lport_notify(struct notifier_block *, unsigned long, void *);
/*
* IO methods.
*/
-void ft_check_stop_free(struct se_cmd *);
+int ft_check_stop_free(struct se_cmd *);
void ft_release_cmd(struct se_cmd *);
int ft_queue_status(struct se_cmd *);
int ft_queue_data_in(struct se_cmd *);
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 80fbcde00cb6..4fac37c4c615 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -19,7 +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>
@@ -113,9 +112,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, 0);
+ transport_generic_free_cmd(se_cmd, 0);
+ return 1;
}
/*
@@ -268,9 +268,8 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
if (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, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
return;
}
@@ -288,7 +287,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
__func__, fh->fh_r_ctl);
ft_invl_hw_context(cmd);
fc_frame_free(fp);
- transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
}
}
@@ -397,7 +396,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
}
pr_debug("alloc tm cmd fn %d\n", tm_func);
- tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
+ tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func, GFP_KERNEL);
if (!tmr) {
pr_debug("alloc failed\n");
ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
@@ -421,7 +420,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
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, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
ft_sess_put(sess);
return;
}
@@ -628,7 +627,7 @@ static void ft_send_work(struct work_struct *work)
if (ret == -ENOMEM) {
transport_send_check_condition_and_sense(se_cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
return;
}
if (ret == -EINVAL) {
@@ -637,10 +636,10 @@ static void ft_send_work(struct work_struct *work)
else
transport_send_check_condition_and_sense(se_cmd,
se_cmd->scsi_sense_reason, 0);
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
return;
}
- transport_generic_handle_cdb(se_cmd);
+ transport_handle_cdb_direct(se_cmd);
return;
err:
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 8fa39b74f22c..5f770412ca40 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -23,7 +23,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>
@@ -32,6 +31,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/configfs.h>
+#include <linux/kernel.h>
#include <linux/ctype.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
@@ -71,10 +71,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
{
const char *cp;
char c;
- u32 nibble;
u32 byte = 0;
u32 pos = 0;
u32 err;
+ int val;
*wwn = 0;
for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) {
@@ -95,13 +95,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
return cp - name;
}
err = 3;
- if (isdigit(c))
- nibble = c - '0';
- else if (isxdigit(c) && (islower(c) || !strict))
- nibble = tolower(c) - 'a' + 10;
- else
+ val = hex_to_bin(c);
+ if (val < 0 || (strict && isupper(c)))
goto fail;
- *wwn = (*wwn << 4) | nibble;
+ *wwn = (*wwn << 4) | val;
}
err = 4;
fail:
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index d35ea5a3d56c..1369b1cb103d 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -28,7 +28,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>
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index dbb5eaeee399..326921385aff 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -19,7 +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>