Blob Blame History Raw
From 709410b1d7f3d0b2b4e342cc46de2b45453d6c5c Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Date: Sat, 18 May 2013 13:56:02 -0700
Subject: [RHEL7 libiscsi PATCH 15/18] TESTS: Add some REPORT SUPPORTED OPCODES tests

Add a simple test that it works or is not implemented.

Add a RCTD test to verify that with this flag clear we get command descriptors without CTDP set  and with it set we get command descriptors with CTDP set and a timeout descriptor

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry-picked from upstream commit 709410b1d7f3d0b2b4e342cc46de2b45453d6c5c)

Fixes these errors in ARM compilation:

lib/scsi-lowlevel.c: In function 'scsi_maintenancein_datain_unmarshall':
lib/scsi-lowlevel.c:862:12: error: cast increases required alignment of target type [-Werror=cast-align]
   datain = (struct scsi_command_descriptor *)&task->datain.data[4];
            ^
lib/scsi-lowlevel.c:876:11: error: cast increases required alignment of target type [-Werror=cast-align]
    desc = (struct scsi_command_descriptor *)((char *)desc + desc_size);
           ^
lib/scsi-lowlevel.c:877:13: error: cast increases required alignment of target type [-Werror=cast-align]
    datain = (struct scsi_command_descriptor *)((char *)datain + desc_size);
             ^
---
 include/scsi-lowlevel.h                          | 60 +++++++-------
 lib/scsi-lowlevel.c                              | 77 +++++++++---------

diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h
index 5693129..acdc936 100644
--- a/include/scsi-lowlevel.h
+++ b/include/scsi-lowlevel.h
@@ -739,24 +739,24 @@ struct scsi_get_lba_status {
 
 struct scsi_op_timeout_descriptor {
 	uint16_t descriptor_length;
-	uint8_t reserved;
 	uint8_t command_specific;
 	uint32_t nominal_processing_timeout;
 	uint32_t recommended_timeout;
 
 };
 struct scsi_command_descriptor {
-	uint8_t op_code;
-	uint8_t reserved1;
-	uint16_t service_action;
-	uint8_t reserved2;
-	uint8_t reserved3;
-	uint16_t cdb_length;
-	struct scsi_op_timeout_descriptor to[0];
+	uint8_t opcode;
+	uint16_t sa;
+	uint8_t ctdp;
+	uint8_t servactv;
+	uint16_t cdb_len;
+
+	/* only present if CTDP==1 */
+	struct scsi_op_timeout_descriptor to;
 };
 
 struct scsi_report_supported_op_codes {
-	uint32_t num_descriptors;
+	int num_descriptors;
 	struct scsi_command_descriptor descriptors[0];
 };
 
diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c
index 3c02ace..c091539 100644
--- a/lib/scsi-lowlevel.c
+++ b/lib/scsi-lowlevel.c
@@ -806,12 +806,6 @@ scsi_persistentreservein_datain_unmarshall(struct scsi_task *task)
 	}
 }
 
-static inline int
-scsi_maintenancein_return_timeouts(const struct scsi_task *task)
-{
-	return task->cdb[2] & 0x80;
-}
-
 static inline uint8_t
 scsi_maintenancein_sa(const struct scsi_task *task)
 {
@@ -841,9 +835,7 @@ static void *
 scsi_maintenancein_datain_unmarshall(struct scsi_task *task)
 {
 	struct scsi_report_supported_op_codes *rsoc;
-	struct scsi_command_descriptor *desc, *datain;
-	uint32_t len, i;
-	int return_timeouts, desc_size;
+	int len, i;
 
 	switch (scsi_maintenancein_sa(task)) {
 	case SCSI_REPORT_SUPPORTED_OP_CODES:
@@ -852,37 +844,52 @@ scsi_maintenancein_datain_unmarshall(struct scsi_task *task)
 		}
 
 		len = task_get_uint32(task, 0);
-		rsoc = scsi_malloc(task, sizeof(struct scsi_report_supported_op_codes) + len);
+		/* len / 8 is not always correct since if CTDP==1 then the
+		 * descriptor is 20 bytes in size intead of 8.
+		 * It doesnt matter here though since it just means we would
+		 * allocate more descriptors at the end of the structure than
+		 * we strictly need. This avoids having to traverse the
+		 * datain buffer twice.
+		 */
+		rsoc = scsi_malloc(task,
+			offsetof(struct scsi_report_supported_op_codes,
+				 descriptors) +
+			len / 8 * sizeof(struct scsi_command_descriptor));
 		if (rsoc == NULL) {
 			return NULL;
 		}
-		/* Does the descriptor include command timeout info? */
-		return_timeouts = scsi_maintenancein_return_timeouts(task);
 
-		/* Size of descriptor depends on whether timeout included. */
-		desc_size = sizeof (struct scsi_command_descriptor);
-		if (return_timeouts) {
-			desc_size += sizeof (struct scsi_op_timeout_descriptor);
-		}
-		rsoc->num_descriptors = len / desc_size;
-
-		desc = &rsoc->descriptors[0];
-		datain = (struct scsi_command_descriptor *)&task->datain.data[4];
-
-		for (i=0; i < rsoc->num_descriptors; i++) {
-			desc->op_code = datain->op_code;
-			desc->service_action = ntohs(datain->service_action);
-			desc->cdb_length =  ntohs(datain->cdb_length);
-			if (return_timeouts) {
-				desc->to[0].descriptor_length = ntohs(datain->to[0].descriptor_length);
-				desc->to[0].command_specific = datain->to[0].command_specific;
-				desc->to[0].nominal_processing_timeout
-					= ntohl(datain->to[0].nominal_processing_timeout);
-				desc->to[0].recommended_timeout
-					= ntohl(datain->to[0].recommended_timeout);
+		rsoc->num_descriptors = 0;
+		i = 4;
+		while (len >= 8) {
+			struct scsi_command_descriptor *desc;
+			
+			desc = &rsoc->descriptors[rsoc->num_descriptors++];
+			desc->opcode = task_get_uint8(task, i);
+			desc->sa = task_get_uint16(task, i + 2);
+			desc->ctdp = !!(task_get_uint8(task, i + 5) & 0x02);
+			desc->servactv = !!(task_get_uint8(task, i + 5) & 0x01);
+			desc->cdb_len = task_get_uint16(task, i + 6);
+
+			len -= 8;
+			i += 8;
+
+			/* No tiemout description */
+			if (!desc->ctdp) {
+				continue;
 			}
-			desc = (struct scsi_command_descriptor *)((char *)desc + desc_size);
-			datain = (struct scsi_command_descriptor *)((char *)datain + desc_size);
+
+			desc->to.descriptor_length =
+				task_get_uint16(task, i);
+			desc->to.command_specific =
+				task_get_uint8(task, i + 3);
+			desc->to.nominal_processing_timeout =
+				task_get_uint32(task, i + 4);
+			desc->to.recommended_timeout =
+				task_get_uint32(task, i + 8);
+
+			len -= desc->to.descriptor_length + 2;
+			i += desc->to.descriptor_length + 2;
 		}
 
 		return rsoc;