]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/target/target_core_transport.c
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / target / target_core_transport.c
index 867bc6d0a68a3ecfbd1aab610f01ff73614b3305..ab2bf12975e1386f51fbd4c94b7d0a79002b7af7 100644 (file)
@@ -281,6 +281,17 @@ struct se_session *transport_init_session_tags(unsigned int tag_num,
        struct se_session *se_sess;
        int rc;
 
+       if (tag_num != 0 && !tag_size) {
+               pr_err("init_session_tags called with percpu-ida tag_num:"
+                      " %u, but zero tag_size\n", tag_num);
+               return ERR_PTR(-EINVAL);
+       }
+       if (!tag_num && tag_size) {
+               pr_err("init_session_tags called with percpu-ida tag_size:"
+                      " %u, but zero tag_num\n", tag_size);
+               return ERR_PTR(-EINVAL);
+       }
+
        se_sess = transport_init_session(sup_prot_ops);
        if (IS_ERR(se_sess))
                return se_sess;
@@ -374,6 +385,51 @@ void transport_register_session(
 }
 EXPORT_SYMBOL(transport_register_session);
 
+struct se_session *
+target_alloc_session(struct se_portal_group *tpg,
+                    unsigned int tag_num, unsigned int tag_size,
+                    enum target_prot_op prot_op,
+                    const char *initiatorname, void *private,
+                    int (*callback)(struct se_portal_group *,
+                                    struct se_session *, void *))
+{
+       struct se_session *sess;
+
+       /*
+        * If the fabric driver is using percpu-ida based pre allocation
+        * of I/O descriptor tags, go ahead and perform that setup now..
+        */
+       if (tag_num != 0)
+               sess = transport_init_session_tags(tag_num, tag_size, prot_op);
+       else
+               sess = transport_init_session(prot_op);
+
+       if (IS_ERR(sess))
+               return sess;
+
+       sess->se_node_acl = core_tpg_check_initiator_node_acl(tpg,
+                                       (unsigned char *)initiatorname);
+       if (!sess->se_node_acl) {
+               transport_free_session(sess);
+               return ERR_PTR(-EACCES);
+       }
+       /*
+        * Go ahead and perform any remaining fabric setup that is
+        * required before transport_register_session().
+        */
+       if (callback != NULL) {
+               int rc = callback(tpg, sess, private);
+               if (rc) {
+                       transport_free_session(sess);
+                       return ERR_PTR(rc);
+               }
+       }
+
+       transport_register_session(tpg, sess->se_node_acl, sess, private);
+       return sess;
+}
+EXPORT_SYMBOL(target_alloc_session);
+
 static void target_release_session(struct kref *kref)
 {
        struct se_session *se_sess = container_of(kref,
@@ -1941,6 +1997,9 @@ static void transport_complete_qf(struct se_cmd *cmd)
 
        switch (cmd->data_direction) {
        case DMA_FROM_DEVICE:
+               if (cmd->scsi_status)
+                       goto queue_status;
+
                trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_data_in(cmd);
                break;
@@ -1951,6 +2010,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
                }
                /* Fall through for DMA_TO_DEVICE */
        case DMA_NONE:
+queue_status:
                trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_status(cmd);
                break;
@@ -2072,6 +2132,9 @@ static void target_complete_ok_work(struct work_struct *work)
 queue_rsp:
        switch (cmd->data_direction) {
        case DMA_FROM_DEVICE:
+               if (cmd->scsi_status)
+                       goto queue_status;
+
                atomic_long_add(cmd->data_length,
                                &cmd->se_lun->lun_stats.tx_data_octets);
                /*
@@ -2111,6 +2174,7 @@ queue_rsp:
                }
                /* Fall through for DMA_TO_DEVICE */
        case DMA_NONE:
+queue_status:
                trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_status(cmd);
                if (ret == -EAGAIN || ret == -ENOMEM)
@@ -2596,8 +2660,6 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
 
        list_for_each_entry_safe(se_cmd, tmp_cmd,
                                &se_sess->sess_wait_list, se_cmd_list) {
-               list_del_init(&se_cmd->se_cmd_list);
-
                pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
                        " %d\n", se_cmd, se_cmd->t_state,
                        se_cmd->se_tfo->get_cmd_state(se_cmd));