From 709410b1d7f3d0b2b4e342cc46de2b45453d6c5c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg 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 (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;