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;