Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Oct 2011 09:17:39 +0000 (11:17 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Oct 2011 09:17:39 +0000 (11:17 +0200)
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (62 commits)
  target: Fix compile warning w/ missing module.h include
  target: Remove legacy se_task->task_timer and associated logic
  target: Fix incorrect transport_sent usage
  target: re-use the command S/G list for single-task commands
  target: Fix BIDI t_task_cdb handling in transport_generic_new_cmd
  target: remove transport_allocate_tasks
  target: merge transport_new_cmd_obj into transport_generic_new_cmd
  target: remove the task_sg_bidi field se_task and pSCSI BIDI support
  target: transport_subsystem_check_init cleanups
  target: use a workqueue for I/O completions
  target: remove unused TRANSPORT_ states
  target: remove TRANSPORT_DEFERRED_CMD state
  target: remove the TRANSPORT_REMOVE state
  target: move depth_left manipulation out of transport_generic_request_failure
  target: stop task timers earlier
  target: remove TF_TIMER_STOP
  target: factor some duplicate code for stopping a task
  target: fix list walking in transport_free_dev_tasks
  target: use transport_cmd_check_stop_to_fabric consistently
  target: do not pass the queue object to transport_remove_cmd_from_queue
  ...

36 files changed:
drivers/target/Makefile
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_tmr.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_alua.c
drivers/target/target_core_cdb.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_file.c
drivers/target/target_core_file.h
drivers/target/target_core_iblock.c
drivers/target/target_core_iblock.h
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_pscsi.h
drivers/target/target_core_rd.c
drivers/target/target_core_rd.h
drivers/target/target_core_scdb.c [deleted file]
drivers/target/target_core_scdb.h [deleted file]
drivers/target/target_core_stat.c
drivers/target/target_core_tmr.c
drivers/target/target_core_transport.c
drivers/target/target_core_ua.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_conf.c
drivers/target/tcm_fc/tfc_io.c
drivers/target/tcm_fc/tfc_sess.c
include/target/target_core_base.h
include/target/target_core_tmr.h
include/target/target_core_transport.h

index 1060c7b7f803d5b2d99cb8396b9e2167af3360db..62e54053bcd870de9f19dfd194ab38ee7895eb88 100644 (file)
@@ -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 \
index 6a4ea29c2f36733206bd49081152dbecf2fcc2df..4d01768fcd90f1483ac0e8d9819ad992b8a46232 100644 (file)
@@ -765,7 +765,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) {
@@ -3538,16 +3538,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 +3932,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 +3939,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);
        }
index 11fd743078117e1ea479117b9facdbbe5d472559..beb39469e7f1e4f91c971f6da468c742a338699d 100644 (file)
@@ -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>
 #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;
index 470ed551eeb52b70909d0a7d638bdb4095918bd2..3723d90d5ae573db84b658fbd70bf2cd7a82bafa 100644 (file)
@@ -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 */
index 91a4d170bda47a5b172842619ecb9cab48d45376..0b8404c30125256a99bff82082516c324ff16364 100644 (file)
@@ -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
                 */
index db1fe1ec84dfd568bed8a61799bdc6443d9f2ab8..490207eacde976a179f1197d21f3901afd1c78e0 100644 (file)
@@ -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;
        }
 
index f00137f377b295f5b1fc0c0873c03c6e60b81e43..02348f727bd4ddaaa4ef4b70e3499fc135001dad 100644 (file)
@@ -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);
index 2cd49d607bda4e0bf9afdaba1e7edba2d50c93f2..835bf7de02815d272476edd071be2b9e4aebe6d3 100644 (file)
@@ -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 *);
index aa2d6799723569a490d566a71c0e7101a82fe407..b15d8cbf630b663065fdad8d77a7dd9b225cb982 100644 (file)
@@ -200,7 +200,7 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
         * 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);
 }
 
 static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
@@ -290,6 +290,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 +375,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 +397,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 +1254,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);
index 98c98a3a0250c9c9b74a373ea346e58a15b32844..8f4447749c7141f245137cddca5bc44ca4d9da48 100644 (file)
@@ -24,7 +24,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/configfs.h>
@@ -68,12 +67,32 @@ 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);
 
        spin_lock(&su_dev->t10_alua.tg_pt_gps_lock);
        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.
index f04d4ef99dca00893761a3fe7c3b93c9dd6ba519..38535eb13929ba5242e128629abfeadae409fc7a 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/ctype.h>
+#include <linux/module.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi.h>
 
@@ -156,11 +156,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 +170,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;
                }
        }
 }
@@ -1266,3 +1266,52 @@ transport_emulate_control_cdb(struct se_task *task)
 
        return PYX_TRANSPORT_SENT_TO_TRANSPORT;
 }
+
+/*
+ * 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;
+               case 10:
+                       /* 32-bit LBA and 16-bit sectors */
+                       put_unaligned_be32(lba, &cdb[2]);
+                       put_unaligned_be16(sectors, &cdb[7]);
+                       break;
+               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();
+               }
+       }
+}
+EXPORT_SYMBOL(target_get_task_cdb);
index b2575d8568cc174ceadb7648c6fa9deb0a438a3f..e0c1e8a8dd4e2140e13d7adedb4c84d414b45725 100644 (file)
@@ -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>
@@ -132,14 +131,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))
index ca6e4a4df134e3b8b64ed093338ef7f11749e499..f870c3bcfd829f1dd68795cd017553441234911f 100644 (file)
@@ -914,21 +914,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 +957,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 +985,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;
index 55bbe0847a6d351cbb2d7ee940fef3f1d194fd10..09b6f8729f918edbcd913770ef73c16485594839 100644 (file)
@@ -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>
index bc1b33639b8d8d0e16c2772ab859da2b63a1c1aa..19a0be9c6570ecb6772ed745549d9b5245c6b787 100644 (file)
@@ -26,7 +26,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/parser.h>
 #include <linux/timer.h>
@@ -273,13 +272,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 +325,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);
@@ -398,33 +399,6 @@ static void fd_emulate_sync_cache(struct se_task *task)
                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 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 +582,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 +613,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 +627,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,
index daebd710b8939bcfc744f35d3a6c25ad872bbd35..59e6e73106c2e638d3785df676836c70c4b9a6b6 100644 (file)
@@ -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
index 7e12341054426404ddd010d793450ca5ac0d7265..41ad02b5fb87d00d558872d85efd5f43344ca0c8 100644 (file)
@@ -27,7 +27,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/parser.h>
 #include <linux/timer.h>
@@ -314,104 +313,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 +362,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 +476,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 +511,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 +556,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 +618,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 +633,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 +666,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,
index a121cd1b657517de83c7931a3e9884b271922786..5cf1860c10d037b92a7a5b0a7c3933273e287856 100644 (file)
@@ -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
index 7fd3a161f7cc61cb8b95b6aca9f6af76972ba44c..0c4f783f924c450efcd82bf91a71027cbf60e508 100644 (file)
@@ -25,7 +25,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
index 2b7b0da9146d3aa9ccf804975d6047afa70166e9..dad671dee9e92172c04142a7dfd4ae6dcc8d206c 100644 (file)
@@ -26,7 +26,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/parser.h>
 #include <linux/timer.h>
@@ -567,7 +566,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 +676,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 +776,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 +959,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 +973,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 +1011,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 +1048,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 (!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 +1214,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 +1234,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,
index ebf4f1ae2c83e78931bee09ae4c65ce64eb2e141..fdc17b6aefb36101325b5bc2b2562fff33fa7c17 100644 (file)
@@ -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;
 
index e567e129c69746b197ab0c2c4e6addfc008a3630..5158d3846f19cf8f79f69e7efe97f72558b0d413 100644 (file)
@@ -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,
index 0d027732cd00215836bb4529d3726382c2baff48..784e56a041001008bdec29f2afd47f11b1d9d31f 100644 (file)
@@ -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 (file)
index 7284344..0000000
+++ /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 (file)
index 48e9ccc..0000000
+++ /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 */
index a8d6e1dee938b418b9c1164ae979acb2a950fbc6..874152aed94af013de0bc5762f0959ea25281e05 100644 (file)
@@ -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>
index 27d4925e51c3f373914fe058630ccda7ccb121c1..570b144a1edb8f0ce696f1f8515b1f74a9317fbc 100644 (file)
@@ -24,7 +24,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
 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 +66,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,54 +100,20 @@ 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.
@@ -169,29 +135,48 @@ 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->tmr_list, &drain_tmr_list);
+       }
+       spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+
+       while (!list_empty(&drain_tmr_list)) {
+               tmr = list_entry(drain_tmr_list.next, struct se_tmr_req, tmr_list);
+               list_del(&tmr->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);
+                       (preempt_and_abort_list) ? "Preempt" : "", tmr,
+                       tmr->function, tmr->response, cmd->t_state);
 
-               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.
         *
@@ -337,11 +330,26 @@ int core_tmr_lun_reset(
                 */
                if (prout_cmd == cmd)
                        continue;
+               /*
+                * Skip direct processing of TRANSPORT_FREE_CMD_INTR for
+                * HW target mode fabrics.
+                */
+               spin_lock(&cmd->t_state_lock);
+               if (cmd->t_state == TRANSPORT_FREE_CMD_INTR) {
+                       spin_unlock(&cmd->t_state_lock);
+                       continue;
+               }
+               spin_unlock(&cmd->t_state_lock);
 
-               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 +362,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 +431,4 @@ int core_tmr_lun_reset(
                        dev->transport->name);
        return 0;
 }
+
index a4b0a8d27f259abd9d57092b814884f55efa3541..d75255804481b8340774e88cf60494eed3c0bd7c 100644 (file)
@@ -26,7 +26,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/net.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include "target_core_alua.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 +69,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 +97,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 +105,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 +120,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 +128,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 +136,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 +144,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 +154,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 +229,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 +252,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)
@@ -438,16 +420,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 +470,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 +487,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);
 
@@ -594,35 +571,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 (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 (!cmd->se_tmr_req)
+               transport_lun_remove_cmd(cmd);
 
        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 +597,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 +627,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 +646,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 +681,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 +696,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 +706,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,68 +725,39 @@ 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);
-
        /*
         * Decrement the outstanding t_task_cdbs_left count.  The last
         * struct se_task from struct se_cmd will complete itself into the
         * 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 (!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 +844,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,38 +874,36 @@ 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);
 }
 
@@ -991,14 +929,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 +988,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 +1473,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,6 +1497,7 @@ 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->t_task_list);
        init_completion(&cmd->transport_lun_fe_stop_comp);
@@ -1641,21 +1541,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 +1552,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
@@ -1729,26 +1608,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 +1632,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.
@@ -1790,7 +1649,7 @@ int transport_handle_cdb_direct(
                return 0;
        else 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 +1670,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 +1700,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,12 +1712,7 @@ 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);
@@ -1866,10 +1720,36 @@ EXPORT_SYMBOL(transport_generic_handle_tmr);
 void transport_generic_free_cmd_intr(
        struct se_cmd *cmd)
 {
-       transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR);
+       transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR, false);
 }
 EXPORT_SYMBOL(transport_generic_free_cmd_intr);
 
+/*
+ * 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)
+{
+       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;
+}
+
 static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
 {
        struct se_task *task, *task_tmp;
@@ -1885,51 +1765,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 +1796,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 +1804,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 +1819,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 +1826,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;
        }
 
@@ -2076,46 +1924,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,153 +1970,32 @@ 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)
+static inline int transport_tcq_window_closed(struct se_device *dev)
 {
-       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);
+       if (dev->dev_tcq_window_closed++ <
+                       PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) {
+               msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT);
+       } else
+               msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG);
 
-       transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE);
+       wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
+       return 0;
 }
 
 /*
- * Called with cmd->t_state_lock held.
+ * Called from Fabric Module context from transport_execute_tasks()
+ *
+ * The return of this function determins if the tasks from struct se_cmd
+ * get added to the execution queue in transport_execute_tasks(),
+ * or are added to the delayed or ordered lists here.
  */
-static void transport_start_task_timer(struct se_task *task)
+static inline int transport_execute_task_attr(struct se_cmd *cmd)
 {
-       struct se_device *dev = task->se_dev;
-       int timeout;
-
-       if (task->task_flags & TF_RUNNING)
-               return;
+       if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+               return 1;
        /*
-        * 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++ <
-                       PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) {
-               msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT);
-       } else
-               msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG);
-
-       wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
-       return 0;
-}
-
-/*
- * Called from Fabric Module context from transport_execute_tasks()
- *
- * The return of this function determins if the tasks from struct se_cmd
- * get added to the execution queue in transport_execute_tasks(),
- * or are added to the delayed or ordered lists here.
- */
-static inline int transport_execute_task_attr(struct se_cmd *cmd)
-{
-       if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
-               return 1;
-       /*
-        * Check for the existence of HEAD_OF_QUEUE, and if true return 1
-        * to allow the passed struct se_cmd list of tasks to the front of the list.
+        * Check for the existence of HEAD_OF_QUEUE, and if true return 1
+        * to allow the passed struct se_cmd list of tasks to the front of the list.
         */
         if (cmd->sam_task_attr == MSG_HEAD_TAG) {
                atomic_inc(&cmd->se_dev->dev_hoq_count);
@@ -2385,7 +2074,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 +2137,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,15 +2145,13 @@ 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
@@ -2477,10 +2162,13 @@ check_depth:
                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);
+                       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);
-                       transport_generic_request_failure(cmd, dev, 0, 1);
+                       atomic_inc(&dev->depth_left);
+                       transport_generic_request_failure(cmd, 0, 1);
                        goto check_depth;
                }
                /*
@@ -2513,10 +2201,13 @@ check_depth:
 
                if (error != 0) {
                        cmd->transport_error_status = error;
-                       atomic_set(&task->task_active, 0);
-                       atomic_set(&cmd->transport_sent, 0);
+                       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);
-                       transport_generic_request_failure(cmd, dev, 0, 1);
+                       atomic_inc(&dev->depth_left);
+                       transport_generic_request_failure(cmd, 0, 1);
                }
        }
 
@@ -2538,8 +2229,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 +2441,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 +2459,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 +2470,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 +2501,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 +2601,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 +2610,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
@@ -2965,7 +2648,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;
@@ -2974,7 +2656,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 +2664,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 +2672,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 +2680,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 +2688,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 +2697,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 +2706,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,18 +2718,14 @@ 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
-                */
-               if (passthrough)
-                       break;
+
+               if (dev->transport->transport_type ==
+                               TRANSPORT_PLUGIN_PHBA_PDEV)
+                       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);
@@ -3078,19 +2749,14 @@ 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
-                        */
                        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);
@@ -3430,7 +3096,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;
        }
 
@@ -3488,8 +3153,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 +3221,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 +3242,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 +3252,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 +3274,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 +3293,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.
@@ -3701,7 +3368,6 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
                break;
        }
 
-done:
        transport_lun_remove_cmd(cmd);
        transport_cmd_check_stop_to_fabric(cmd);
        return;
@@ -3709,34 +3375,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 +3431,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;
-       }
-       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;
+               if (!atomic_dec_and_test(&cmd->t_se_count))
+                       goto out_busy;
        }
 
-       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 +3509,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 +3619,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 +3655,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 +3719,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 +3734,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 +3765,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 +3772,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 +3787,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 +3814,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 +3870,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 +3888,15 @@ 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);
+       if (cmd->se_tfo->write_pending(cmd) == -EAGAIN) {
+               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 +3906,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
@@ -4386,61 +3930,52 @@ 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);
+       transport_handle_queue_full(cmd, cmd->se_dev);
        return ret;
 }
 
+/**
+ * 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);
        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)
-{
-       return;
-}
-
 /*     transport_lun_wait_for_tasks():
  *
  *     Called from ConfigFS context to stop the passed struct se_cmd to allow
@@ -4479,7 +4014,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 +4145,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)
+void 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;
+       }
+       /*
+        * 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;
+       }
        /*
         * 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 +4208,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;
+       }
 
        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 +4233,10 @@ 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);
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 }
+EXPORT_SYMBOL(transport_wait_for_tasks);
 
 static int transport_get_sense_codes(
        struct se_cmd *cmd,
@@ -4920,6 +4461,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 +4534,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 +4557,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 +4565,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 +4577,17 @@ 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) {
                                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 +4595,22 @@ 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);
+                       transport_generic_free_cmd(cmd, 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 +4621,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;
 }
index 31e3c652527e0d3999983f022fd1a5627a99ed63..50a480db7a66df3d619e103060ca6c1be301f9b4 100644 (file)
@@ -24,7 +24,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <scsi/scsi.h>
index 80fbcde00cb694db7a628d3e0c0362a3e47650cd..6195026cc7b02bb908cecd6ed32f9527a3b34399 100644 (file)
@@ -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>
@@ -115,7 +114,7 @@ void ft_release_cmd(struct se_cmd *se_cmd)
 
 void ft_check_stop_free(struct se_cmd *se_cmd)
 {
-       transport_generic_free_cmd(se_cmd, 0, 0);
+       transport_generic_free_cmd(se_cmd, 0);
 }
 
 /*
@@ -268,9 +267,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 +286,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 +395,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 +419,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 +626,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 +635,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:
index 8fa39b74f22c4a178ed714f123131521f0d78e84..5f770412ca403265ddfc19856ef4934470a25c63 100644 (file)
@@ -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:
index d35ea5a3d56c159d96eaaa533abe3fd8f34f9843..1369b1cb103d7d1e0ad4053322e599713445e9b7 100644 (file)
@@ -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>
index dbb5eaeee39984445e673ee2ea9b8064752b3804..326921385aff973c17ce4f8598ba791c0fa94fc2 100644 (file)
@@ -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>
index 27040653005e42f8d4babb506b7badd209cca014..35aa786f93da35a8fa1d6b8859ae6ced92f6ff9e 100644 (file)
 #include <net/tcp.h>
 
 #define TARGET_CORE_MOD_VERSION                "v4.1.0-rc1-ml"
-#define SHUTDOWN_SIGS  (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT))
 
-/* Used by transport_generic_allocate_iovecs() */
-#define TRANSPORT_IOV_DATA_BUFFER              5
 /* Maximum Number of LUNs per Target Portal Group */
 /* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */
 #define TRANSPORT_MAX_LUNS_PER_TPG             256
@@ -75,32 +72,26 @@ enum transport_tpg_type_table {
 };
 
 /* Used for generate timer flags */
-enum timer_flags_table {
-       TF_RUNNING      = 0x01,
-       TF_STOP         = 0x02,
+enum se_task_flags {
+       TF_ACTIVE               = (1 << 0),
+       TF_SENT                 = (1 << 1),
+       TF_REQUEST_STOP         = (1 << 2),
 };
 
 /* Special transport agnostic struct se_cmd->t_states */
 enum transport_state_table {
        TRANSPORT_NO_STATE      = 0,
        TRANSPORT_NEW_CMD       = 1,
-       TRANSPORT_DEFERRED_CMD  = 2,
        TRANSPORT_WRITE_PENDING = 3,
        TRANSPORT_PROCESS_WRITE = 4,
        TRANSPORT_PROCESSING    = 5,
-       TRANSPORT_COMPLETE_OK   = 6,
-       TRANSPORT_COMPLETE_FAILURE = 7,
-       TRANSPORT_COMPLETE_TIMEOUT = 8,
+       TRANSPORT_COMPLETE      = 6,
        TRANSPORT_PROCESS_TMR   = 9,
-       TRANSPORT_TMR_COMPLETE  = 10,
        TRANSPORT_ISTATE_PROCESSING = 11,
-       TRANSPORT_ISTATE_PROCESSED = 12,
-       TRANSPORT_KILL          = 13,
-       TRANSPORT_REMOVE        = 14,
-       TRANSPORT_FREE          = 15,
        TRANSPORT_NEW_CMD_MAP   = 16,
        TRANSPORT_FREE_CMD_INTR = 17,
        TRANSPORT_COMPLETE_QF_WP = 18,
+       TRANSPORT_COMPLETE_QF_OK = 19,
 };
 
 /* Used for struct se_cmd->se_cmd_flags */
@@ -125,7 +116,6 @@ enum se_cmd_flags_table {
        SCF_UNUSED                      = 0x00100000,
        SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
        SCF_EMULATE_CDB_ASYNC           = 0x01000000,
-       SCF_EMULATE_QUEUE_FULL          = 0x02000000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -401,34 +391,22 @@ struct se_queue_obj {
 } ____cacheline_aligned;
 
 struct se_task {
-       unsigned char   task_sense;
-       struct scatterlist *task_sg;
-       u32             task_sg_nents;
-       struct scatterlist *task_sg_bidi;
-       u8              task_scsi_status;
-       u8              task_flags;
-       int             task_error_status;
-       int             task_state_flags;
-       bool            task_padded_sg;
        unsigned long long      task_lba;
-       u32             task_no;
-       u32             task_sectors;
-       u32             task_size;
+       u32                     task_sectors;
+       u32                     task_size;
+       struct se_cmd           *task_se_cmd;
+       struct scatterlist      *task_sg;
+       u32                     task_sg_nents;
+       u16                     task_flags;
+       u8                      task_sense;
+       u8                      task_scsi_status;
+       int                     task_error_status;
        enum dma_data_direction task_data_direction;
-       struct se_cmd *task_se_cmd;
-       struct se_device        *se_dev;
+       atomic_t                task_state_active;
+       struct list_head        t_list;
+       struct list_head        t_execute_list;
+       struct list_head        t_state_list;
        struct completion       task_stop_comp;
-       atomic_t        task_active;
-       atomic_t        task_execute_queue;
-       atomic_t        task_timeout;
-       atomic_t        task_sent;
-       atomic_t        task_stop;
-       atomic_t        task_state_active;
-       struct timer_list       task_timer;
-       struct se_device *se_obj_ptr;
-       struct list_head t_list;
-       struct list_head t_execute_list;
-       struct list_head t_state_list;
 } ____cacheline_aligned;
 
 struct se_cmd {
@@ -446,8 +424,6 @@ struct se_cmd {
        int                     sam_task_attr;
        /* Transport protocol dependent state, see transport_state_table */
        enum transport_state_table t_state;
-       /* Transport protocol dependent state for out of order CmdSNs */
-       int                     deferred_t_state;
        /* Transport specific error status */
        int                     transport_error_status;
        /* See se_cmd_flags_table */
@@ -461,7 +437,6 @@ struct se_cmd {
        u32                     orig_fe_lun;
        /* Persistent Reservation key */
        u64                     pr_res_key;
-       atomic_t                transport_sent;
        /* Used for sense data */
        void                    *sense_buffer;
        struct list_head        se_delayed_node;
@@ -479,10 +454,7 @@ struct se_cmd {
        struct list_head        se_queue_node;
        struct target_core_fabric_ops *se_tfo;
        int (*transport_emulate_cdb)(struct se_cmd *);
-       void (*transport_split_cdb)(unsigned long long, u32, unsigned char *);
-       void (*transport_wait_for_tasks)(struct se_cmd *, int, int);
        void (*transport_complete_callback)(struct se_cmd *);
-       int (*transport_qf_callback)(struct se_cmd *);
 
        unsigned char           *t_task_cdb;
        unsigned char           __t_task_cdb[TCM_MAX_COMMAND_SIZE];
@@ -495,7 +467,6 @@ struct se_cmd {
        atomic_t                t_se_count;
        atomic_t                t_task_cdbs_left;
        atomic_t                t_task_cdbs_ex_left;
-       atomic_t                t_task_cdbs_timeout_left;
        atomic_t                t_task_cdbs_sent;
        atomic_t                t_transport_aborted;
        atomic_t                t_transport_active;
@@ -503,7 +474,6 @@ struct se_cmd {
        atomic_t                t_transport_queue_active;
        atomic_t                t_transport_sent;
        atomic_t                t_transport_stop;
-       atomic_t                t_transport_timeout;
        atomic_t                transport_dev_active;
        atomic_t                transport_lun_active;
        atomic_t                transport_lun_fe_stop;
@@ -514,6 +484,8 @@ struct se_cmd {
        struct completion       transport_lun_stop_comp;
        struct scatterlist      *t_tasks_sg_chained;
 
+       struct work_struct      work;
+
        /*
         * Used for pre-registered fabric SGL passthrough WRITE and READ
         * with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop
@@ -670,7 +642,6 @@ struct se_dev_attrib {
        u32             optimal_sectors;
        u32             hw_queue_depth;
        u32             queue_depth;
-       u32             task_timeout;
        u32             max_unmap_lba_count;
        u32             max_unmap_block_desc_count;
        u32             unmap_granularity;
index bd559680747812a53db6f1e6722cecb1c7fae789..d5876e17d3fb0670cce3cbb9e6664797114097dd 100644 (file)
@@ -27,7 +27,7 @@ enum tcm_tmrsp_table {
 
 extern struct kmem_cache *se_tmr_req_cache;
 
-extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8);
+extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
 extern void core_tmr_release_req(struct se_tmr_req *);
 extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
                                struct list_head *, struct se_cmd *);
index 46aae4f94ede427814b6f6cdef7974c1f89d5fd3..a037a1a6fbbac5d0d2219c8cc7a53edf023ba653 100644 (file)
 #define PYX_TRANSPORT_LU_COMM_FAILURE          -7
 #define PYX_TRANSPORT_UNKNOWN_MODE_PAGE                -8
 #define PYX_TRANSPORT_WRITE_PROTECTED          -9
-#define PYX_TRANSPORT_TASK_TIMEOUT             -10
-#define PYX_TRANSPORT_RESERVATION_CONFLICT     -11
-#define PYX_TRANSPORT_ILLEGAL_REQUEST          -12
-#define PYX_TRANSPORT_USE_SENSE_REASON         -13
+#define PYX_TRANSPORT_RESERVATION_CONFLICT     -10
+#define PYX_TRANSPORT_ILLEGAL_REQUEST          -11
+#define PYX_TRANSPORT_USE_SENSE_REASON         -12
 
 #ifndef SAM_STAT_RESERVATION_CONFLICT
 #define SAM_STAT_RESERVATION_CONFLICT          0x18
 #define TRANSPORT_PLUGIN_VHBA_PDEV             2
 #define TRANSPORT_PLUGIN_VHBA_VDEV             3
 
-/* For SE OBJ Plugins, in seconds */
-#define TRANSPORT_TIMEOUT_TUR                  10
-#define TRANSPORT_TIMEOUT_TYPE_DISK            60
-#define TRANSPORT_TIMEOUT_TYPE_ROM             120
-#define TRANSPORT_TIMEOUT_TYPE_TAPE            600
-#define TRANSPORT_TIMEOUT_TYPE_OTHER           300
-
-/* For se_task->task_state_flags */
-#define TSF_EXCEPTION_CLEARED                  0x01
-
 /*
  * struct se_subsystem_dev->su_dev_flags
 */
@@ -64,8 +53,6 @@
 #define DF_SPC2_RESERVATIONS_WITH_ISID         0x00000004
 
 /* struct se_dev_attrib sanity values */
-/* 10 Minutes */
-#define DA_TASK_TIMEOUT_MAX                    600
 /* Default max_unmap_lba_count */
 #define DA_MAX_UNMAP_LBA_COUNT                 0
 /* Default max_unmap_block_desc_count */
 
 #define MOD_MAX_SECTORS(ms, bs)                        (ms % (PAGE_SIZE / bs))
 
-struct se_mem;
 struct se_subsystem_api;
 
-extern struct kmem_cache *se_mem_cache;
-
 extern int init_se_kmem_caches(void);
 extern void release_se_kmem_caches(void);
 extern u32 scsi_get_new_index(scsi_index_t);
 extern void transport_init_queue_obj(struct se_queue_obj *);
-extern int transport_subsystem_check_init(void);
+extern void transport_subsystem_check_init(void);
 extern int transport_subsystem_register(struct se_subsystem_api *);
 extern void transport_subsystem_release(struct se_subsystem_api *);
 extern void transport_load_plugins(void);
@@ -134,7 +118,6 @@ extern void transport_free_session(struct se_session *);
 extern void transport_deregister_session_configfs(struct se_session *);
 extern void transport_deregister_session(struct se_session *);
 extern void transport_cmd_finish_abort(struct se_cmd *, int);
-extern void transport_cmd_finish_abort_tmr(struct se_cmd *);
 extern void transport_complete_sync_cache(struct se_cmd *, int);
 extern void transport_complete_task(struct se_task *, int);
 extern void transport_add_task_to_execute_queue(struct se_task *,
@@ -142,6 +125,8 @@ extern void transport_add_task_to_execute_queue(struct se_task *,
                                                struct se_device *);
 extern void transport_remove_task_from_execute_queue(struct se_task *,
                                                struct se_device *);
+extern void __transport_remove_task_from_execute_queue(struct se_task *,
+                                               struct se_device *);
 unsigned char *transport_dump_cmd_direction(struct se_cmd *);
 extern void transport_dump_dev_state(struct se_device *, char *, int *);
 extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
@@ -169,29 +154,24 @@ extern void transport_init_se_cmd(struct se_cmd *,
                                        unsigned char *);
 void *transport_kmap_first_data_page(struct se_cmd *cmd);
 void transport_kunmap_first_data_page(struct se_cmd *cmd);
-extern void transport_free_se_cmd(struct se_cmd *);
 extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
-extern int transport_generic_handle_cdb(struct se_cmd *);
 extern int transport_handle_cdb_direct(struct se_cmd *);
 extern int transport_generic_handle_cdb_map(struct se_cmd *);
 extern int transport_generic_handle_data(struct se_cmd *);
 extern void transport_new_cmd_failure(struct se_cmd *);
 extern int transport_generic_handle_tmr(struct se_cmd *);
 extern void transport_generic_free_cmd_intr(struct se_cmd *);
-extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
+extern bool target_stop_task(struct se_task *task, unsigned long *flags);
 extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
                                struct scatterlist *, u32);
 extern int transport_clear_lun_from_sessions(struct se_lun *);
+extern void transport_wait_for_tasks(struct se_cmd *);
 extern int transport_check_aborted_status(struct se_cmd *, int);
 extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
 extern void transport_send_task_abort(struct se_cmd *);
 extern void transport_release_cmd(struct se_cmd *);
-extern void transport_generic_free_cmd(struct se_cmd *, int, int);
+extern void transport_generic_free_cmd(struct se_cmd *, int);
 extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
-extern int transport_init_task_sg(struct se_task *, struct se_mem *, u32);
-extern int transport_map_mem_to_sg(struct se_task *, struct list_head *,
-                                       struct scatterlist *, struct se_mem *,
-                                       struct se_mem **, u32 *, u32 *);
 extern void transport_do_task_sg_chain(struct se_cmd *);
 extern void transport_generic_process_write(struct se_cmd *);
 extern int transport_generic_new_cmd(struct se_cmd *);
@@ -200,6 +180,7 @@ extern int transport_generic_do_tmr(struct se_cmd *);
 extern int core_alua_check_nonop_delay(struct se_cmd *);
 /* From target_core_cdb.c */
 extern int transport_emulate_control_cdb(struct se_task *);
+extern void target_get_task_cdb(struct se_task *task, unsigned char *cdb);
 
 /*
  * Each se_transport_task_t can have N number of possible struct se_task's
@@ -227,6 +208,10 @@ struct se_subsystem_api {
         * Transport Type.
         */
        u8 transport_type;
+
+       unsigned int fua_write_emulated : 1;
+       unsigned int write_cache_emulated : 1;
+
        /*
         * struct module for struct se_hba references
         */
@@ -235,18 +220,6 @@ struct se_subsystem_api {
         * Used for global se_subsystem_api list_head
         */
        struct list_head sub_api_list;
-       /*
-        * For SCF_SCSI_NON_DATA_CDB
-        */
-       int (*cdb_none)(struct se_task *);
-       /*
-        * For SCF_SCSI_DATA_SG_IO_CDB
-        */
-       int (*map_data_SG)(struct se_task *);
-       /*
-        * For SCF_SCSI_CONTROL_SG_IO_CDB
-        */
-       int (*map_control_SG)(struct se_task *);
        /*
         * attach_hba():
         */
@@ -274,22 +247,6 @@ struct se_subsystem_api {
         */
        void (*free_device)(void *);
 
-       /*
-        * dpo_emulated():
-        */
-       int (*dpo_emulated)(struct se_device *);
-       /*
-        * fua_write_emulated():
-        */
-       int (*fua_write_emulated)(struct se_device *);
-       /*
-        * fua_read_emulated():
-        */
-       int (*fua_read_emulated)(struct se_device *);
-       /*
-        * write_cache_emulated():
-        */
-       int (*write_cache_emulated)(struct se_device *);
        /*
         * transport_complete():
         *
@@ -330,10 +287,6 @@ struct se_subsystem_api {
         */
        ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
                                                char *);
-       /*
-        * get_cdb():
-        */
-       unsigned char *(*get_cdb)(struct se_task *);
        /*
         * get_device_rev():
         */
This page took 0.159639 seconds and 5 git commands to generate.