Add support for pdu digest offload and payload direct-placement capabilities.

Signed-off-by: Karen Xie <[EMAIL PROTECTED]>
---

 drivers/scsi/iscsi_tcp.c            |   58 ++++++++++++++++++++++++-----------
 drivers/scsi/iscsi_tcp.h            |   14 ++++++++
 drivers/scsi/libiscsi.c             |   51 ++++++++++++++++++++++++-------
 include/scsi/iscsi_if.h             |    1 +
 include/scsi/libiscsi.h             |    2 +
 include/scsi/scsi_transport_iscsi.h |    9 +++++
 6 files changed, 104 insertions(+), 31 deletions(-)


diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 29bf0b5..8e2848e 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -97,7 +97,7 @@ static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn 
*tcp_conn,
  * data is copied to the indicated sg entry, at the given
  * offset.
  */
-static inline void
+void
 iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
                          struct scatterlist *sg, unsigned int offset)
 {
@@ -107,6 +107,7 @@ iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
                            segment->total_size - segment->total_copied);
        segment->data = NULL;
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_segment_init_sg);
 
 /**
  * iscsi_tcp_segment_map - map the current S/G page
@@ -117,7 +118,7 @@ iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
  * because the iscsi passthrough and internal IO paths will never use high
  * mem pages.
  */
-static inline void
+void
 iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
 {
        struct scatterlist *sg;
@@ -143,8 +144,9 @@ iscsi_tcp_segment_map(struct iscsi_segment *segment, int 
recv)
        segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
        segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_segment_map);
 
-static inline void
+void
 iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
 {
        debug_tcp("iscsi_tcp_segment_unmap %p\n", segment);
@@ -156,6 +158,7 @@ iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
                segment->data = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_segment_unmap);
 
 /*
  * Splice the digest buffer into the buffer
@@ -376,6 +379,8 @@ static inline int
 iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
                      struct iscsi_segment *segment)
 {
+       if (tcp_conn->iscsi_conn->session->tt->caps & CAP_DIGEST_OFFLOAD)
+               return ((segment->status & ISCSI_SEGMENT_DGST_ERR) ? 0 : 1);
        if (!segment->digest_len)
                return 1;
 
@@ -448,7 +453,7 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
  * function is called we do not yet know the final size of the header and want
  * to delay the digest processing until we know that.
  */
-static void
+void
 iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
 {
        debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn,
@@ -457,6 +462,7 @@ iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
                                tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
                                iscsi_tcp_hdr_recv_done, NULL);
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_recv_prep);
 
 /*
  * Handle incoming reply to any other type of command
@@ -486,7 +492,8 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
        struct iscsi_conn *conn = tcp_conn->iscsi_conn;
        struct hash_desc *rx_hash = NULL;
 
-       if (conn->datadgst_en)
+       if (conn->datadgst_en &&
+           !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
                rx_hash = &tcp_conn->rx_hash;
 
        iscsi_segment_init_linear(&tcp_conn->in.segment,
@@ -497,7 +504,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
 /*
  * must be called with session lock
  */
-static void
+void
 iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task)
 {
        struct iscsi_tcp_task *tcp_task = task->dd_data;
@@ -521,6 +528,7 @@ iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct 
iscsi_task *task)
                tcp_task->r2t = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
 
 /**
  * iscsi_data_rsp - SCSI Data-In Response processing
@@ -737,7 +745,7 @@ iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
  * by data, the receive buffer is set up to copy the incoming data
  * to the correct location.
  */
-static int
+int
 iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 {
        int rc = 0, opcode, ahslen;
@@ -793,7 +801,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct 
iscsi_hdr *hdr)
                         * we move on to the next scatterlist entry and
                         * update the digest per-entry.
                         */
-                       if (conn->datadgst_en)
+                       if (conn->datadgst_en &&
+                           !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
                                rx_hash = &tcp_conn->rx_hash;
 
                        debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
@@ -881,6 +890,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct 
iscsi_hdr *hdr)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_dissect);
 
 /**
  * iscsi_tcp_hdr_recv_done - process PDU header
@@ -919,7 +929,8 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
        /* We're done processing the header. See if we're doing
         * header digests; if so, set up the recv_digest buffer
         * and go back for more. */
-       if (conn->hdrdgst_en) {
+       if (conn->hdrdgst_en &&
+           !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
                if (segment->digest_len == 0) {
                        iscsi_tcp_segment_splice_digest(segment,
                                                        segment->recv_digest);
@@ -944,7 +955,8 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
  * @offset: offset in skb
  * @len: skb->len - offset
  **/
-static int
+
+int
 iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
               unsigned int offset, size_t len)
 {
@@ -1158,7 +1170,7 @@ iscsi_tcp_xmit_qlen(struct iscsi_conn *conn)
        return segment->total_copied - segment->total_size;
 }
 
-static inline int
+static int
 iscsi_tcp_flush(struct iscsi_conn *conn)
 {
        int rc;
@@ -1205,7 +1217,8 @@ iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void 
*hdr, size_t hdrlen)
         * sure that both iscsi_tcp_task and mtask have
         * sufficient room.
         */
-       if (conn->hdrdgst_en) {
+       if (conn->hdrdgst_en &&
+           !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
                iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen,
                                      hdr + hdrlen);
                hdrlen += ISCSI_DIGEST_SIZE;
@@ -1243,7 +1256,8 @@ iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct 
scatterlist *sg,
        hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
        WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
 
-       if (conn->datadgst_en)
+       if (conn->datadgst_en &&
+           !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
                tx_hash = &tcp_conn->tx_hash;
 
        return iscsi_segment_seek_sg(&tcp_conn->out.data_segment,
@@ -1267,7 +1281,8 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn 
*conn, void *data,
        hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
        WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
 
-       if (conn->datadgst_en)
+       if (conn->datadgst_en &&
+           !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
                tx_hash = &tcp_conn->tx_hash;
 
        iscsi_segment_init_linear(&tcp_conn->out.data_segment,
@@ -1329,7 +1344,7 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct 
iscsi_task *task,
  * @task: scsi command task
  * @sc: scsi command
  **/
-static int
+int
 iscsi_tcp_task_init(struct iscsi_task *task)
 {
        struct iscsi_tcp_task *tcp_task = task->dd_data;
@@ -1378,6 +1393,7 @@ iscsi_tcp_task_init(struct iscsi_task *task)
        task->imm_count = 0;
        return 0;
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_task_init);
 
 /*
  * iscsi_tcp_task_xmit - xmit normal PDU task
@@ -1387,7 +1403,7 @@ iscsi_tcp_task_init(struct iscsi_task *task)
  * -EAGAIN if there's still data in the queue, or != 0 for any other kind
  * of error.
  */
-static int
+int
 iscsi_tcp_task_xmit(struct iscsi_task *task)
 {
        struct iscsi_conn *conn = task->conn;
@@ -1398,7 +1414,7 @@ iscsi_tcp_task_xmit(struct iscsi_task *task)
 
 flush:
        /* Flush any pending data first. */
-       rc = iscsi_tcp_flush(conn);
+       rc = conn->session->tt->flush_conn(conn);
        if (rc < 0)
                return rc;
 
@@ -1490,6 +1506,7 @@ fail:
        iscsi_conn_failure(conn, rc);
        return -EIO;
 }
+EXPORT_SYMBOL_GPL(iscsi_tcp_task_xmit);
 
 static struct iscsi_cls_conn *
 iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
@@ -1696,7 +1713,7 @@ free_socket:
        return err;
 }
 
-static int
+int
 iscsi_r2tpool_alloc(struct iscsi_session *session)
 {
        int i;
@@ -1742,8 +1759,9 @@ r2t_alloc_fail:
        }
        return -ENOMEM;
 }
+EXPORT_SYMBOL_GPL(iscsi_r2tpool_alloc);
 
-static void
+void
 iscsi_r2tpool_free(struct iscsi_session *session)
 {
        int i;
@@ -1756,6 +1774,7 @@ iscsi_r2tpool_free(struct iscsi_session *session)
                iscsi_pool_free(&tcp_task->r2tpool);
        }
 }
+EXPORT_SYMBOL_GPL(iscsi_r2tpool_free);
 
 static int
 iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
@@ -1981,6 +2000,7 @@ static struct iscsi_transport iscsi_tcp_transport = {
        .get_session_param      = iscsi_session_get_param,
        .start_conn             = iscsi_conn_start,
        .stop_conn              = iscsi_tcp_conn_stop,
+       .flush_conn             = iscsi_tcp_flush,
        /* iscsi host params */
        .get_host_param         = iscsi_host_get_param,
        .set_host_param         = iscsi_host_set_param,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 498d8ca..62747c7 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -32,7 +32,9 @@ struct iscsi_segment;
 typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
                                    struct iscsi_segment *);
 
+#define ISCSI_SEGMENT_DGST_ERR 0x1
 struct iscsi_segment {
+       unsigned int            status;
        unsigned char           *data;
        unsigned int            size;
        unsigned int            copied;
@@ -130,4 +132,16 @@ struct iscsi_tcp_task {
        struct iscsi_data_task  unsol_dtask;    /* Data-Out header buf */
 };
 
+void iscsi_tcp_segment_init_sg(struct iscsi_segment *, struct scatterlist *,
+                              unsigned int);
+void iscsi_tcp_segment_map(struct iscsi_segment *, int);
+void iscsi_tcp_segment_unmap(struct iscsi_segment *);
+void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *);
+void iscsi_tcp_cleanup_task(struct iscsi_conn *, struct iscsi_task *);
+int iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *);
+int iscsi_tcp_task_init(struct iscsi_task *);
+int iscsi_tcp_task_xmit(struct iscsi_task *);
+int iscsi_r2tpool_alloc(struct iscsi_session *);
+void iscsi_r2tpool_free(struct iscsi_session *);
+
 #endif /* ISCSI_H */
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 5b9699f..84b381b 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -218,7 +218,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
        hdr->opcode = ISCSI_OP_SCSI_CMD;
        hdr->flags = ISCSI_ATTR_SIMPLE;
        int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-       hdr->itt = build_itt(task->itt, session->age);
+       if (session->tt->reserve_itt) {
+               rc = session->tt->reserve_itt(task, &hdr->itt);
+               if (rc)
+                       return rc;
+       } else
+               hdr->itt = build_itt(task->itt, session->age);
        hdr->cmdsn = cpu_to_be32(session->cmdsn);
        session->cmdsn++;
        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
@@ -332,6 +337,9 @@ static void iscsi_complete_command(struct iscsi_task *task)
        struct iscsi_session *session = conn->session;
        struct scsi_cmnd *sc = task->sc;
 
+       if (session->tt->release_itt)
+               session->tt->release_itt(task, task->hdr->itt);
+
        list_del_init(&task->running);
        task->state = ISCSI_TASK_COMPLETED;
        task->sc = NULL;
@@ -443,7 +451,12 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
         */
        nop->cmdsn = cpu_to_be32(session->cmdsn);
        if (hdr->itt != RESERVED_ITT) {
-               hdr->itt = build_itt(task->itt, session->age);
+               if (session->tt->reserve_itt) {
+                       int rc = session->tt->reserve_itt(task, &hdr->itt);
+                       if (rc)
+                               return rc;
+               } else
+                       hdr->itt = build_itt(task->itt, session->age);
                /*
                 * TODO: We always use immediate, so we never hit this.
                 * If we start to send tmfs or nops as non-immediate then
@@ -692,7 +705,12 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, 
struct iscsi_hdr *hdr,
 
                if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
                        memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
-                       itt = get_itt(rejected_pdu.itt);
+                       if (conn->session->tt->parse_itt) {
+                               conn->session->tt->parse_itt(conn,
+                                                            rejected_pdu.itt,
+                                                            &itt, NULL);
+                       } else
+                               itt = get_itt(rejected_pdu.itt);
                        iscsi_conn_printk(KERN_ERR, conn,
                                          "itt 0x%x had pdu (op 0x%x) rejected "
                                          "due to DataDigest error.\n", itt,
@@ -720,7 +738,10 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn 
*conn, itt_t itt)
        if (itt == RESERVED_ITT)
                return NULL;
 
-       i = get_itt(itt);
+       if (session->tt->parse_itt)
+               session->tt->parse_itt(conn, itt, &i, NULL);
+       else
+               i = get_itt(itt);
        if (i >= session->cmds_max)
                return NULL;
 
@@ -752,9 +773,12 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct 
iscsi_hdr *hdr,
        if (rc)
                return rc;
 
-       if (hdr->itt != RESERVED_ITT)
-               itt = get_itt(hdr->itt);
-       else
+       if (hdr->itt != RESERVED_ITT) {
+               if (session->tt->parse_itt)
+                       session->tt->parse_itt(conn, hdr->itt, &itt, NULL);
+               else
+                       itt = get_itt(hdr->itt);
+       } else
                itt = ~0U;
 
        debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n",
@@ -901,20 +925,25 @@ EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
 int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
 {
        struct iscsi_session *session = conn->session;
-       uint32_t i;
+       uint32_t i, age;
 
        if (itt == RESERVED_ITT)
                return 0;
 
-       if (((__force u32)itt & ISCSI_AGE_MASK) !=
-           (session->age << ISCSI_AGE_SHIFT)) {
+       if (session->tt->parse_itt)
+               session->tt->parse_itt(conn, itt, &i, &age);
+       else {
+               i = get_itt(itt);
+               age = ((__force u32)itt >> ISCSI_AGE_SHIFT) & ISCSI_AGE_MASK;
+       }
+
+       if (age != session->age) {
                iscsi_conn_printk(KERN_ERR, conn,
                                  "received itt %x expected session age (%x)\n",
                                  (__force u32)itt, session->age);
                return ISCSI_ERR_BAD_ITT;
        }
 
-       i = get_itt(itt);
        if (i >= session->cmds_max) {
                iscsi_conn_printk(KERN_ERR, conn,
                                  "received invalid itt index %u (max cmds "
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index f274d24..f4abac2 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -334,6 +334,7 @@ enum iscsi_host_param {
 #define CAP_FW_DB              0x200
 #define CAP_SENDTARGETS_OFFLOAD        0x400
 #define CAP_DATA_PATH_OFFLOAD  0x800
+#define CAP_DIGEST_OFFLOAD     0x1000
 
 /*
  * These flags describes reason of stop_conn() call
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 7872bbc..313aa94 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -74,8 +74,8 @@ enum {
 #define ISCSI_TOTAL_CMDS_MAX           4096
 /* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
 #define ISCSI_TOTAL_CMDS_MIN           16
+#define ISCSI_AGE_MASK                 0xf
 #define ISCSI_AGE_SHIFT                        28
-#define ISCSI_AGE_MASK                 (0xf << ISCSI_AGE_SHIFT)
 
 #define ISCSI_ADDRESS_BUF_LEN          64
 
diff --git a/include/scsi/scsi_transport_iscsi.h 
b/include/scsi/scsi_transport_iscsi.h
index f5444e0..0cf2c93 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -56,6 +56,10 @@ struct sockaddr;
  *                     is not supported, and a -Exx value on other error
  * @start_conn:                set connection to be operational
  * @stop_conn:         suspend/recover/terminate connection
+ * @flush_conn:                flush a connection's transmit queue
+ * @parse_itt:         parse the itt rcv'ed in BHS
+ * @reserve_itt:       construct a task itt to be sent in BHS
+ * @release_itt:       release a itt (constructed by reserve_itt)
  * @send_pdu:          send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
  * @session_recovery_timedout: notify LLD a block during recovery timed out
  * @init_task:         Initialize a iscsi_task and any internal structs.
@@ -113,6 +117,11 @@ struct iscsi_transport {
                         char *data, uint32_t data_size);
        void (*get_stats) (struct iscsi_cls_conn *conn,
                           struct iscsi_stats *stats);
+       int (*flush_conn) (struct iscsi_conn *conn);
+       void (*parse_itt)(struct iscsi_conn *conn, itt_t hdr_itt,
+                        int *idx, int *age);
+       int (*reserve_itt)(struct iscsi_task *task, itt_t *hdr_itt);
+       void (*release_itt)(struct iscsi_task *task, itt_t hdr_itt);
        int (*init_task) (struct iscsi_task *task);
        int (*xmit_task) (struct iscsi_task *task);
        void (*cleanup_task) (struct iscsi_conn *conn,







--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To post to this group, send email to open-iscsi@googlegroups.com
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