lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Wed, 27 Aug 2008 21:21:59 -0700
From:	Karen Xie <kxie@...lsio.com>
To:	netdev@...r.kernel.org, open-iscsi@...glegroups.com,
	linux-scsi@...r.kernel.org, linux-kernel@...r.kernel.org
Cc:	jgarzik@...ox.com, davem@...emloft.net, michaelc@...wisc.edu,
	swise@...ngridcomputing.com, rdreier@...co.com, daisyc@...ibm.com,
	wenxiong@...ibm.com, bhua@...ibm.com, divy@...lsio.com,
	dm@...lsio.com, leedom@...lsio.com, kxie@...lsio.com
Subject: [PATCH 3/4 2.6.28] open-iscsi - support for digest offload and payload DDP

[PATCH 3/4 2.6.28] open-iscsi - support for digest offload and payload DDP.

From: Karen Xie <kxie@...lsio.com>

Added PDU digest offload and payload direct-placement support in
open-iscsi.

Signed-off-by: Karen Xie <kxie@...lsio.com>
---

 drivers/scsi/iscsi_tcp.c            |   56 ++++++++++++++++++++++++-----------
 drivers/scsi/iscsi_tcp.h            |   14 +++++++++
 drivers/scsi/libiscsi.c             |   54 +++++++++++++++++++++++++++-------
 include/scsi/iscsi_if.h             |    1 +
 include/scsi/libiscsi.h             |    2 +
 include/scsi/scsi_transport_iscsi.h |    9 ++++++
 6 files changed, 106 insertions(+), 30 deletions(-)


diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 2a2f009..ec73a31 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,9 @@ 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 +454,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 +463,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 +493,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 +505,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 +529,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 +746,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 +802,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 +891,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 +930,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);
@@ -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,
@@ -1978,6 +1997,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..81ed0fb 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 299e075..9c8eb4c 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;
@@ -442,7 +450,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
@@ -691,7 +704,13 @@ 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,
@@ -719,7 +738,11 @@ static 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 (conn->session->tt->parse_itt)
+		conn->session->tt->parse_itt(conn, itt, &i, NULL);
+	else
+		i = get_itt(itt);
+
 	if (i >= session->cmds_max)
 		return NULL;
 
@@ -750,9 +773,13 @@ 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 (conn->session->tt->parse_itt)
+			conn->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",
@@ -899,20 +926,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 (conn->session->tt->parse_itt)
+		conn->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 16be12f..75afc58 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -333,6 +333,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 5e75bb7..31f916f 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -75,7 +75,7 @@ enum {
 /* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
 #define ISCSI_TOTAL_CMDS_MIN		16
 #define ISCSI_AGE_SHIFT			28
-#define ISCSI_AGE_MASK			(0xf << ISCSI_AGE_SHIFT)
+#define ISCSI_AGE_MASK			0xf
 
 #define ISCSI_ADDRESS_BUF_LEN		64
 
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 8b6c91d..eb4e34c 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.
@@ -109,6 +113,11 @@ struct iscsi_transport {
 	int (*set_host_param) (struct Scsi_Host *shost,
 			       enum iscsi_host_param param, char *buf,
 			       int buflen);
+	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 (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
 			 char *data, uint32_t data_size);
 	void (*get_stats) (struct iscsi_cls_conn *conn,
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ