[Stgt-devel] [PATCH] parse iscsi AHS header for extended CDB

Pete Wyckoff pw
Mon Mar 5 21:37:22 CET 2007


Modify iscsi target code to understand AHS header when it contains
an extended CDB, and pass this into target for processing.  Assumes
panasas bidirectional patches to the kernel to pickup struct
iscsi_ecdb_ahdr.

Signed-off-by: Pete Wyckoff <pw at osc.edu>
---
 usr/iscsi/iscsid.c |  125 +++++++++++++++++++++++++++++++++-------------------
 usr/iscsi/iscsid.h |    2 +
 2 files changed, 81 insertions(+), 46 deletions(-)

diff --git a/usr/iscsi/iscsid.c b/usr/iscsi/iscsid.c
index 3178df6..9c326dc 100644
--- a/usr/iscsi/iscsid.c
+++ b/usr/iscsi/iscsid.c
@@ -3,6 +3,7 @@
  *
  * (C) 2005-2006 FUJITA Tomonori <tomof at acm.org>
  * (C) 2005-2006 Mike Christie <michaelc at cs.wisc.edu>
+ * (C) 2007 Pete Wyckoff <pw at osc.edu>
  *
  * This code is based on Ardis's iSCSI implementation.
  *   http://www.ardistech.com/iscsi/
@@ -902,7 +903,9 @@ static void iscsi_free_cmd_task(struct iscsi_task *task)
 	target_cmd_done(conn->session->iscsi_nexus_id, task->tag);
 	list_del(&task->c_hlist);
 	if (task->c_buffer) {
-		if ((unsigned long) task->c_buffer != task->addr)
+		/* task->data was set on the input, if not changed, no
+		 * buffer was allocated by scsi layer */
+		if ((unsigned long) task->data != task->addr)
 			free((void *) (unsigned long) task->addr);
 	}
 	iscsi_free_task(task);
@@ -976,29 +979,43 @@ static int iscsi_scsi_cmd_execute(struct iscsi_task *task)
 {
 	struct iscsi_connection *conn = task->conn;
 	struct iscsi_cmd *req = (struct iscsi_cmd *) &task->req;
-	unsigned long uaddr = (unsigned long) task->c_buffer;
+	unsigned long uaddr = (unsigned long) task->data;
+	uint8_t rw = req->flags & ISCSI_FLAG_CMD_WRITE;
+	uint8_t *cdb, cdbbuf[260];
+	int cdblen;
 	int err = 0;
 
-	if (req->flags & ISCSI_FLAG_CMD_WRITE) {
-		if (task->r2t_count) {
-			if (task->unsol_count)
-				;
-			else
-				list_add_tail(&task->c_list, &task->conn->tx_clist);
-		} else
-			err = target_cmd_queue(conn->session->iscsi_nexus_id,
-					       req->cdb, 16,
-					       req->flags & ISCSI_FLAG_CMD_WRITE,
-					       uaddr, req->lun,
-					       ntohl(req->data_length),
-					       cmd_attr(task), req->itt);
-	} else
-		err = target_cmd_queue(conn->session->iscsi_nexus_id,
-				       req->cdb, 16,
-				       req->flags & ISCSI_FLAG_CMD_WRITE,
-				       uaddr, req->lun, ntohl(req->data_length),
-				       cmd_attr(task), req->itt);
+	if (rw && task->r2t_count) {
+		if (!task->unsol_count)
+			list_add_tail(&task->c_list, &task->conn->tx_clist);
+		goto noqueue;
+	}
+
+	cdb = req->cdb;
+	cdblen = 16;
+	if (req->hlength) {
+		/* concatenate extended cdb */
+		struct iscsi_ecdb_ahdr *ahs_extcdb = task->ahs;
+		if (ahs_extcdb->ahstype == ISCSI_AHSTYPE_CDB) {
+			int extlen = ntohs(ahs_extcdb->ahslength) - 1;
+			dprintf("extcdb len %d\n", extlen);
+			if (extlen + 16 > sizeof(cdbbuf)) {
+				err = -ENOMEM;
+				goto noqueue;
+			}
+			memcpy(cdbbuf, cdb, 16);
+			memcpy(cdbbuf + 16, ahs_extcdb->ecdb, extlen);
+			cdb = cdbbuf;
+			cdblen = 16 + extlen;
+		}
+	}
+
+	err = target_cmd_queue(conn->session->iscsi_nexus_id,
+			       cdb, cdblen, rw, uaddr, req->lun,
+			       ntohl(req->data_length),
+			       cmd_attr(task), req->itt);
 
+noqueue:
 	tgt_event_modify(conn->fd, EPOLLIN|EPOLLOUT);
 
 	return err;
@@ -1222,6 +1239,7 @@ static int iscsi_scsi_cmd_rx_start(struct iscsi_connection *conn)
 {
 	struct iscsi_cmd *req = (struct iscsi_cmd *) &conn->req.bhs;
 	struct iscsi_task *task;
+	int ahslen, ahslen_round, dlen, dlen_round, tot_data_length;
 	int len;
 
 	task = __iscsi_task_rx_start(conn);
@@ -1229,26 +1247,45 @@ static int iscsi_scsi_cmd_rx_start(struct iscsi_connection *conn)
 		return -ENOMEM;
 	task->tag = req->itt;
 
-	dprintf("%u %x %d %d %x\n", conn->session->tsih,
+	ahslen = req->hlength * 4;
+	dlen = ntoh24(req->dlength);  /* just part in this PDU */
+	tot_data_length = ntohl(req->data_length);  /* all data */
+
+	dprintf("%u %x %d %d %x task %p lens %d %d %d\n", conn->session->tsih,
 		req->cdb[0], ntohl(req->data_length),
-		req->flags & ISCSI_FLAG_CMD_ATTR_MASK, req->itt);
+		req->flags & ISCSI_FLAG_CMD_ATTR_MASK, req->itt,
+		task, ahslen, dlen, tot_data_length);
 
-	len = ntohl(req->data_length);
-	if (len) {
-		task->c_buffer = valloc(len);
+	/*
+	 * Allocate both AHS space from this PDU, and data from this
+	 * and all subsequent PDUs, at once.  Since the AHS and initial
+	 * data segments are padded to 4-byte boundaries, space things
+	 * so that a single read() does the right thing.
+	 */
+	if (ahslen || tot_data_length) {
+		/* round up each separately */
+		ahslen_round = (ahslen + 3) & ~3;
+		dlen_round = (dlen + 3) & ~3;
+		len = tot_data_length;  /* make sure to alloc padding */
+		if (len < dlen_round)
+			len = dlen_round;
+		task->c_buffer = valloc(ahslen_round + len);
 		if (!task->c_buffer) {
 			iscsi_free_task(task);
 			return -ENOMEM;
 		}
-		dprintf("%p\n", task->c_buffer);
+		task->ahs = task->c_buffer;
+		task->data = task->c_buffer + ahslen_round;
+
+		/* next amount to read from this PDU, and where to put it */
+		conn->rx_size = ahslen_round + dlen_round;
+		conn->rx_buffer = task->c_buffer;
 	}
 
 	if (req->flags & ISCSI_FLAG_CMD_WRITE) {
-		conn->rx_size = ntoh24(req->dlength);
-		conn->rx_buffer = task->c_buffer;
-		task->r2t_count = ntohl(req->data_length) - conn->rx_size;
+		task->r2t_count = tot_data_length - dlen;  /* bytes left */
 		task->unsol_count = !(req->flags & ISCSI_FLAG_CMD_FINAL);
-		task->offset = conn->rx_size;
+		task->offset = dlen;
 
 		dprintf("%d %d %d %d\n", conn->rx_size, task->r2t_count,
 			task->unsol_count, task->offset);
@@ -1582,35 +1619,31 @@ static void iscsi_rx_handler(int fd, struct iscsi_connection *conn)
 
 		switch (conn->rx_iostate) {
 		case IOSTATE_READ_BHS:
-			conn->rx_iostate = IOSTATE_READ_AHS_DATA;
 			conn->req.ahssize = conn->req.bhs.hlength * 4;
 			conn->req.datasize = ntoh24(conn->req.bhs.dlength);
-			conn->rx_size = (conn->req.ahssize + conn->req.datasize + 3) & -4;
-
-			if (conn->req.ahssize) {
-				eprintf("FIXME: we cannot handle ahs\n");
-				conn->state = STATE_CLOSE;
-				break;
-			}
 
 			if (conn->state == STATE_SCSI) {
+				/* sets up rx_buffer and rx_size */
 				res = iscsi_task_rx_start(conn);
 				if (res) {
 					conn->state = STATE_CLOSE;
 					break;
 				}
+			} else {
+				/* use req_buffer to store the bits */
+				conn->rx_buffer = conn->req_buffer;
+				conn->req.ahs = conn->rx_buffer;
+				conn->rx_size = (conn->req.ahssize + 3) & ~3;
+				conn->req.data = conn->rx_buffer + conn->rx_size;
+				conn->rx_size += (conn->req.datasize + 3) & ~3;
 			}
-
 			if (conn->rx_size) {
-				if (conn->state != STATE_SCSI) {
-					conn->rx_buffer = conn->req_buffer;
-					conn->req.ahs = conn->rx_buffer;
-				}
-				conn->req.data =
-					conn->rx_buffer + conn->req.ahssize;
+				conn->rx_iostate = IOSTATE_READ_AHS_DATA;
 				goto read_again;
 			}
 
+			/* fall through */
+
 		case IOSTATE_READ_AHS_DATA:
 			if (conn->state == STATE_SCSI) {
 				res = iscsi_task_rx_done(conn);
diff --git a/usr/iscsi/iscsid.h b/usr/iscsi/iscsid.h
index 4887043..ea09967 100644
--- a/usr/iscsi/iscsid.h
+++ b/usr/iscsi/iscsid.h
@@ -112,6 +112,8 @@ struct iscsi_task {
 	int exp_r2tsn;
 
 	void *c_buffer;
+	void *ahs;  /* these point into c_buffer, parts after bhs */
+	void *data;
 
 	/*
 	 * temp hack.
-- 
1.5.0.2




More information about the stgt mailing list