This patch adds the code to iSCSI to make use of the dmaengine. If
CONFIG_ISCSI_DMA is enabled then we offload copying skb bits to
dma_skb_copy_bits. The implementation of this patch is fairly simple
and should be easy to follow.

Signed-off-by: Supreeth Venkataraman <[EMAIL PROTECTED]>
---

 drivers/scsi/iscsi_tcp.c |   72 ++++++++++++++++++++++++++++-
 drivers/scsi/libiscsi.c  |  115 ++++++++++++++++++++++++++++++++++++++
++++++++
 include/scsi/libiscsi.h  |   14 ++++++
 3 files changed, 200 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 57ce225..d0d546f 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -33,6 +33,7 @@
 #include <linux/blkdev.h>
 #include <linux/crypto.h>
 #include <linux/delay.h>
+#include <linux/smp.h>
 #include <linux/kfifo.h>
 #include <linux/scatterlist.h>
 #include <net/tcp.h>
@@ -42,6 +43,10 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_transport_iscsi.h>

+#ifdef CONFIG_ISCSI_DMA
+#include <net/netdma.h>
+#endif /* CONFIG_ISCSI_DMA */
+
 #include "iscsi_tcp.h"

 MODULE_AUTHOR("Dmitry Yusupov <[EMAIL PROTECTED]>, "
@@ -587,7 +592,7 @@ copy_hdr:
  *     ctask->data_count       left to copy from in progress Data-In
  *     buf_left                left to copy from in progress buffer
  **/
-static inline int
+int
 iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct
iscsi_cmd_task *ctask,
                void *buf, int buf_size, int offset)
 {
@@ -596,6 +601,10 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn,
struct iscsi_cmd_task *ctask,
        unsigned size = min(tcp_conn->in.copy, buf_left);
        int rc;

+#ifdef CONFIG_ISCSI_DMA
+       dma_cookie_t cookie;
+#endif /* CONFIG_ISCSI_DMA */
+
        size = min(size, ctask->data_count);

        debug_tcp("ctask_copy %d bytes at offset %d copied %d\n",
@@ -604,8 +613,22 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn,
struct iscsi_cmd_task *ctask,
        BUG_ON(size <= 0);
        BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));

+#ifdef CONFIG_ISCSI_DMA
+       if (tcp_conn->iscsi_conn->dma_chan) {
+               rc = dma_skb_copy_bits(tcp_conn->iscsi_conn->dma_chan, tcp_conn-
>in.skb, tcp_conn->in.offset,
+                                      (char*)buf + (offset + 
tcp_conn->data_copied), size,
+                                      &cookie);
+               if (0 < cookie)
+                       tcp_conn->iscsi_conn->dma_cookie = cookie;
+
+       } else {
+               rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
+                                  (char*)buf + (offset + 
tcp_conn->data_copied), size);
+       }
+#else
        rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
                           (char*)buf + (offset + tcp_conn->data_copied), size);
+#endif /* CONFIG_ISCSI_DMA */
        /* must fit into skb->len */
        BUG_ON(rc);

@@ -756,6 +779,42 @@ static int iscsi_scsi_data_in(struct iscsi_conn
*conn)

        /* check for non-exceptional status */
        if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+#ifdef CONFIG_ISCSI_DMA
+               if (0 < tcp_conn->iscsi_conn->dma_cookie) {
+                       struct sk_buff *skb;
+                       struct sock *sk;
+                       dma_cookie_t done, used, skb_cookie = 0;
+
+                       sk = tcp_conn->sock->sk;
+
+                       
dma_async_memcpy_issue_pending(tcp_conn->iscsi_conn->dma_chan);
+
+                       while (dma_async_memcpy_complete(tcp_conn-
>iscsi_conn->dma_chan,
+                                                         tcp_conn-
>iscsi_conn->dma_cookie, &done,
+                                                         &used) ==
DMA_IN_PROGRESS) {
+                                /* do partial cleanup of
sk_async_wait_queue up to done*/
+                               do
+                               {
+                                       skb = 
skb_peek(&sk->sk_async_wait_queue);
+
+                                       if (NULL == skb || done < 
skb->dma_cookie)
+                                               break;
+                                       else {
+                                               skb_cookie = skb->dma_cookie;
+                                               
__skb_dequeue(&sk->sk_async_wait_queue);
+                                                kfree_skb(skb);
+                                       }
+                               } while (skb_cookie != done);
+                        }
+
+                       /* Safe to free early-copied skbs now */
+                       __skb_queue_purge(&sk->sk_async_wait_queue);
+                       tcp_conn->iscsi_conn->dma_cookie = 0;
+               }
+
+               if ( tcp_conn->iscsi_conn->dma_chan)
+                       dma_chan_put(tcp_conn->iscsi_conn->dma_chan);
+#endif /* CONFIG_ISCSI_DMA */
                debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
                           (long)sc, sc->result, ctask->itt,
                           tcp_conn->in.hdr->flags);
@@ -1955,6 +2014,10 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session
*cls_session,
        sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
        sk->sk_allocation = GFP_ATOMIC;

+#ifdef CONFIG_ISCSI_DMA
+       skb_queue_head_init(&sk->sk_async_wait_queue);
+#endif /* CONFIG_ISCSI_DMA */
+
        /* FIXME: disable Nagle's algorithm */

        /*
@@ -2305,6 +2368,10 @@ iscsi_tcp_init(void)
        if (!iscsi_register_transport(&iscsi_tcp_transport))
                return -ENODEV;

+#ifdef CONFIG_ISCSI_DMA
+       iscsi_register_dma();
+#endif /* CONFIG_ISCSI_DMA */
+
        return 0;
 }

@@ -2312,6 +2379,9 @@ static void __exit
 iscsi_tcp_exit(void)
 {
        iscsi_unregister_transport(&iscsi_tcp_transport);
+#ifdef CONFIG_ISCSI_DMA
+       iscsi_unregister_dma();
+#endif /* CONFIG_ISCSI_DMA */
 }

 module_init(iscsi_tcp_init);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8b57af5..2d7cc2c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -23,7 +23,11 @@
  */
 #include <linux/types.h>
 #include <linux/kfifo.h>
+#include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/rcupdate.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
 #include <asm/unaligned.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
@@ -37,6 +41,28 @@
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/libiscsi.h>

+#ifdef CONFIG_ISCSI_DMA
+#include <linux/dmaengine.h>
+
+struct iscsi_dma {
+  struct dma_client client;
+  spinlock_t lock;
+  cpumask_t channel_mask;
+  struct dma_chan *channel[NR_CPUS];
+};
+
+static enum dma_state_client
+iscsi_dma_event(struct dma_client *client, struct dma_chan *chan,
+               enum dma_state state);
+
+static struct iscsi_dma iscsi_dma = {
+  .client = {
+    .event_callback = iscsi_dma_event,
+  },
+};
+#endif /* CONFIG_ISCSI_DMA */
+
+
 struct iscsi_session *
 class_to_transport_session(struct iscsi_cls_session *cls_session)
 {
@@ -291,6 +317,9 @@ invalid_datalen:
                           min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
        }

+       if (sc->sc_data_direction == DMA_TO_DEVICE)
+               goto out;
+
        if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
                int res_count = be32_to_cpu(rhdr->residual_count);

@@ -1534,6 +1563,7 @@ iscsi_conn_setup(struct iscsi_cls_session
*cls_session, uint32_t conn_idx)
        struct iscsi_conn *conn;
        struct iscsi_cls_conn *cls_conn;
        char *data;
+    int id = 0;

        cls_conn = iscsi_create_conn(cls_session, conn_idx);
        if (!cls_conn)
@@ -1546,6 +1576,17 @@ iscsi_conn_setup(struct iscsi_cls_session
*cls_session, uint32_t conn_idx)
        conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
        conn->id = conn_idx;
        conn->exp_statsn = 0;
+
+#ifdef CONFIG_ISCSI_DMA
+    id = smp_processor_id();
+       if (iscsi_dma.channel[id]) {
+               printk(KERN_INFO "iscsi_conn_setup: %d \n",id);
+                 dma_chan_get(iscsi_dma.channel[id]);
+                 conn->dma_chan = iscsi_dma.channel[id];
+       }
+       conn->dma_cookie = 0;
+#endif  /*CONFIG_ISCSI_DMA*/
+
        conn->tmabort_state = TMABORT_INITIAL;
        INIT_LIST_HEAD(&conn->run_list);
        INIT_LIST_HEAD(&conn->mgmt_run_list);
@@ -2135,6 +2176,80 @@ int iscsi_host_set_param(struct Scsi_Host
*shost, enum iscsi_host_param param,
 }
 EXPORT_SYMBOL_GPL(iscsi_host_set_param);

+#ifdef CONFIG_ISCSI_DMA
+/**
+ * iscsi_dma_event - event callback for the iscsi_dma_client
+ * @client: should always be iscsi_dma_client
+ * @chan: DMA channel for the event
+ * @event: event type
+ */
+static enum dma_state_client iscsi_dma_event(struct dma_client
*client,
+            struct dma_chan *chan, enum dma_state event)
+{
+    int i, found = 0, pos = -1;
+       struct iscsi_dma *iscsi_dma =
+               container_of(client, struct iscsi_dma, client);
+       enum dma_state_client ack = DMA_DUP; /* default: take no action */
+
+       spin_lock(&iscsi_dma->lock);
+       switch (event) {
+       case DMA_RESOURCE_AVAILABLE:
+               for (i = 0; i < NR_CPUS; i++)
+                       if (iscsi_dma->channel[i] == chan) {
+                               found = 1;
+                               break;
+                       } else if (iscsi_dma->channel[i] == NULL && pos < 0)
+                               pos = i;
+
+               if (!found && pos >= 0) {
+                       ack = DMA_ACK;
+                       iscsi_dma->channel[pos] = chan;
+                       cpu_set(pos, iscsi_dma->channel_mask);
+                       //iscsi_dma_rebalance(iscsi_dma);
+               }
+               break;
+       case DMA_RESOURCE_REMOVED:
+               for (i = 0; i < NR_CPUS; i++)
+                       if (iscsi_dma->channel[i] == chan) {
+                               found = 1;
+                               pos = i;
+                               break;
+                       }
+
+               if (found) {
+                       ack = DMA_ACK;
+                       cpu_clear(pos, iscsi_dma->channel_mask);
+                       iscsi_dma->channel[i] = NULL;
+                       //iscsi_dma_rebalance(net_dma);
+               }
+               break;
+       default:
+               break;
+       }
+       spin_unlock(&iscsi_dma->lock);
+
+       return ack;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_dma_event);
+
+int iscsi_register_dma(void)
+{
+       spin_lock_init(&iscsi_dma.lock);
+       dma_cap_set(DMA_MEMCPY, iscsi_dma.client.cap_mask);
+       dma_async_client_register(&iscsi_dma.client);
+        dma_async_client_chan_request(&iscsi_dma.client);
+        return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_register_dma);
+
+void iscsi_unregister_dma(void)
+{
+       dma_async_client_unregister(&iscsi_dma.client);
+}
+EXPORT_SYMBOL_GPL(iscsi_unregister_dma);
+#endif /* CONFIG_ISCSI_DMA */
+
 MODULE_AUTHOR("Mike Christie");
 MODULE_DESCRIPTION("iSCSI library functions");
 MODULE_LICENSE("GPL");
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index b4b3113..b443282 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -27,8 +27,13 @@
 #include <linux/mutex.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/cpumask.h>
 #include <scsi/iscsi_proto.h>
 #include <scsi/iscsi_if.h>
+#include <scsi/iscsi_if.h>
+#ifdef CONFIG_ISCSI_DMA
+#include <linux/dmaengine.h>
+#endif /* CONFIG_ISCSI_DMA */

 struct scsi_transport_template;
 struct scsi_device;
@@ -196,6 +201,10 @@ struct iscsi_conn {

        /* custom statistics */
        uint32_t                eh_abort_cnt;
+#ifdef CONFIG_ISCSI_DMA
+       struct dma_chan         *dma_chan;       /* DMA channel for copies
*/
+       dma_cookie_t            dma_cookie;      /* last DMA cookie returned
for this ctask */
+#endif /* CONFIG_ISCSI_DMA */
 };

 struct iscsi_queue {
@@ -333,4 +342,9 @@ extern int iscsi_verify_itt(struct iscsi_conn *,
struct iscsi_hdr *,
 extern void iscsi_pool_free(struct iscsi_queue *, void **);
 extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int);

+/*
+ * DMA functions
+ */
+extern int iscsi_register_dma(void);
+extern void iscsi_unregister_dma(void);
 #endif



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/open-iscsi
-~----------~----~----~----~------~----~------~--~---

Reply via email to