From 1c3e2083c9f61a1e065cb9e353195cad6e9b1538 Mon Sep 17 00:00:00 2001 From: Ser01x Date: Wed, 21 Jul 2021 16:28:16 +0000 Subject: [PATCH 1/3] lib: init version for 8Fh VPD page The third-party copy (8Fh) VPD page helps to check the capabilities supported by the copy manager. --- include/scsi-lowlevel.h | 27 ++++++++++++ lib/scsi-lowlevel.c | 93 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 2561b01..e10620d 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -536,6 +536,7 @@ enum scsi_inquiry_pagecode { SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES = 0x00, SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER = 0x80, SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION = 0x83, + SCSI_INQUIRY_PAGECODE_THIRD_PARTY_COPY = 0x8F, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS = 0xB0, SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS = 0xB1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING = 0xB2 @@ -687,6 +688,32 @@ struct scsi_inquiry_device_identification { struct scsi_inquiry_device_designator *designators; }; +enum third_party_copy_descriptor_type { + THIRD_PARTY_COPY_TYPE_SUPPORTED_COMMANDS = 0x0001 +}; + +struct third_party_copy_command_support { + struct third_party_copy_command_support *next; + + int operation_code; + int service_action_length; + int *service_action; +}; + +struct third_party_copy_supported_commands { + enum third_party_copy_descriptor_type descriptor_type; + + struct third_party_copy_command_support *commands_supported; +}; + +struct scsi_inquiry_third_party_copy { + enum scsi_inquiry_peripheral_qualifier qualifier; + enum scsi_inquiry_peripheral_device_type device_type; + enum scsi_inquiry_pagecode pagecode; + + struct third_party_copy_supported_commands *supported_commands; +}; + /* * MODESENSE */ diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 50ec515..fc47b61 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -1495,6 +1495,97 @@ scsi_inquiry_unmarshall_device_identification(struct scsi_task *task) return NULL; } +static struct third_party_copy_supported_commands * +third_party_copy_unmarshall_supported_commands(struct scsi_task *task, + unsigned char *dptr) +{ + struct third_party_copy_supported_commands *supported_commands = + scsi_malloc(task, sizeof(*supported_commands)); + int remaining; + unsigned char *lptr; + + if (supported_commands == NULL) { + return NULL; + } + + supported_commands->descriptor_type = scsi_get_uint16(&dptr[0]); + + remaining = dptr[4]; + lptr = &dptr[5]; + while (remaining > 0) { + struct third_party_copy_command_support *command = + scsi_malloc(task, sizeof(*command)); + int i; + + if (command == NULL) { + goto err; + } + + command->next = supported_commands->commands_supported; + supported_commands->commands_supported = command; + + command->operation_code = lptr[0]; + command->service_action_length = lptr[1]; + command->service_action = scsi_malloc(task, + sizeof(*command->service_action) * (command->service_action_length + 1)); + if (command->service_action == NULL) { + goto err; + } + command->service_action[command->service_action_length] = 0; + for (i = 0; i < command->service_action_length; i++) { + command->service_action[i] = lptr[2 + i]; + } + + remaining -= command->service_action_length + 2; + lptr += command->service_action_length + 2; + } + return supported_commands; + +err: + return NULL; +} + +static struct scsi_inquiry_third_party_copy * +scsi_inquiry_unmarshall_third_party_copy(struct scsi_task *task) +{ + struct scsi_inquiry_third_party_copy *inq = scsi_malloc(task, + sizeof(*inq)); + int remaining; + unsigned char *dptr; + + if (inq == NULL) { + return NULL; + } + + inq->qualifier = (task_get_uint8(task, 0) >> 5) & 0x07; + inq->device_type = task_get_uint8(task, 0) & 0x1f; + inq->pagecode = task_get_uint8(task, 1); + + remaining = task_get_uint16(task, 2); + dptr = &task->datain.data[4]; + while (remaining > 0) { + int copy_desc_type = scsi_get_uint16(&dptr[0]); + int copy_desc_len = scsi_get_uint16(&dptr[2]); + + switch (copy_desc_type) { + case THIRD_PARTY_COPY_TYPE_SUPPORTED_COMMANDS: + inq->supported_commands = + third_party_copy_unmarshall_supported_commands(task, dptr); + if (inq->supported_commands == NULL) { + goto err; + } + break; + } + + remaining -= copy_desc_len + 4; + dptr += copy_desc_len + 4; + } + return inq; + +err: + return NULL; +} + static struct scsi_inquiry_block_limits * scsi_inquiry_unmarshall_block_limits(struct scsi_task *task) { @@ -1597,6 +1688,8 @@ scsi_inquiry_datain_unmarshall(struct scsi_task *task) return scsi_inquiry_unmarshall_unit_serial_number(task); case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: return scsi_inquiry_unmarshall_device_identification(task); + case SCSI_INQUIRY_PAGECODE_THIRD_PARTY_COPY: + return scsi_inquiry_unmarshall_third_party_copy(task); case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: return scsi_inquiry_unmarshall_block_limits(task); case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: From 053c6db9e128e5ece737867cd2e150f79433b6d5 Mon Sep 17 00:00:00 2001 From: Ser01x Date: Wed, 21 Jul 2021 16:37:57 +0000 Subject: [PATCH 2/3] test-tool: check that ReceiveCopyResults is implemented We check that the RECEIVE COPY STATUS(LID1) command is supported by SCSI device before sending it. --- .../test_receive_copy_results_copy_status.c | 106 +++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/test-tool/test_receive_copy_results_copy_status.c b/test-tool/test_receive_copy_results_copy_status.c index 71af29a..dbefe7e 100644 --- a/test-tool/test_receive_copy_results_copy_status.c +++ b/test-tool/test_receive_copy_results_copy_status.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -26,19 +27,112 @@ #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" + + void test_receive_copy_results_copy_status(void) { - struct scsi_task *cs_task; + struct scsi_task *cs_task = NULL; struct scsi_copy_results_copy_status *csp; int tgt_desc_len = 0, seg_desc_len = 0; int offset = XCOPY_DESC_OFFSET, list_id = 1; struct iscsi_data data; unsigned char *xcopybuf; + struct scsi_inquiry_supported_pages *sup_inq; + struct scsi_inquiry_third_party_copy *third_party_inq; + struct third_party_copy_command_support *command; + bool third_party_page_supported = false; + bool receive_copy_results_supported = false; + int ret, i; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test RECEIVE COPY RESULTS, COPY STATUS"); + logging(LOG_VERBOSE, "Get VPD pages supported list."); + ret = inquiry(sd, &task, + 1, SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES, 255, + EXPECT_STATUS_GOOD); + CU_ASSERT_EQUAL(ret, 0); + if (ret != 0) { + logging(LOG_NORMAL, "[FAILED] Failed to get Supported VPD Pages."); + return; + } + + logging(LOG_VERBOSE, "Check that RECEIVE COPY RESULTS is supported."); + sup_inq = scsi_datain_unmarshall(task); + CU_ASSERT_NOT_EQUAL(sup_inq, NULL); + if (sup_inq == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to unmarshall DATA-IN " + "buffer."); + return; + } + + for (i = 0; i < sup_inq->num_pages; i++) { + if (sup_inq->pages[i] == SCSI_INQUIRY_PAGECODE_THIRD_PARTY_COPY) { + third_party_page_supported = true; + break; + } + } + if (!third_party_page_supported) { + logging(LOG_NORMAL, "[SKIPPED] Third-party Copy VPD page is not " + "implemented."); + CU_PASS("RECEIVE COPY RESULTS is not implemented."); + goto finished; + } + logging(LOG_VERBOSE, "Third-party Copy VPD page is supported."); + + scsi_free_scsi_task(task); + task = NULL; + + ret = inquiry(sd, &task, + 1, SCSI_INQUIRY_PAGECODE_THIRD_PARTY_COPY, 1024, + EXPECT_STATUS_GOOD); + CU_ASSERT_EQUAL(ret, 0); + if (ret != 0) { + logging(LOG_NORMAL, "[FAILED] Failed to get Third-party Copy " + "VPD page."); + return; + } + + third_party_inq = scsi_datain_unmarshall(task); + CU_ASSERT_NOT_EQUAL(third_party_inq, NULL); + if (third_party_inq == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to unmarshall DATA-IN " + "buffer."); + return; + } + CU_ASSERT_NOT_EQUAL(third_party_inq->supported_commands, NULL); + if (third_party_inq->supported_commands == NULL) { + logging(LOG_NORMAL, "[FAILED] Supported Commands descriptor is " + "is not found."); + return; + } + + command = third_party_inq->supported_commands->commands_supported; + while (command && !receive_copy_results_supported) { + if (command->operation_code == SCSI_OPCODE_RECEIVE_COPY_RESULTS) { + for (i = 0; i < command->service_action_length; i++) { + if (command->service_action[i] == + SCSI_COPY_RESULTS_COPY_STATUS) { + receive_copy_results_supported = true; + break; + } + } + } + + command = command->next; + } + if (!receive_copy_results_supported) { + logging(LOG_NORMAL, "[SKIPPED] RECEIVE COPY RESULTS is not " + "implemented."); + CU_PASS("RECEIVE COPY RESULTS is not implemented."); + goto finished; + } + logging(LOG_VERBOSE, "RECEIVE COPY RESULTS is supported."); + + scsi_free_scsi_task(task); + task = NULL; + logging(LOG_VERBOSE, "No copy in progress"); RECEIVE_COPY_RESULTS(&cs_task, sd, SCSI_COPY_RESULTS_COPY_STATUS, list_id, NULL, EXPECT_INVALID_FIELD_IN_CDB); @@ -76,5 +170,13 @@ test_receive_copy_results_copy_status(void) RECEIVE_COPY_RESULTS(&cs_task, sd, SCSI_COPY_RESULTS_COPY_STATUS, list_id, (void **)&csp, EXPECT_STATUS_GOOD); - scsi_free_scsi_task(cs_task); +finished: + if (task != NULL) { + scsi_free_scsi_task(task); + task = NULL; + } + if (cs_task != NULL) { + scsi_free_scsi_task(cs_task); + cs_task = NULL; + } } From e8c15866fa49271365b65a36938e0d961d4fa281 Mon Sep 17 00:00:00 2001 From: Ser01x Date: Mon, 26 Jul 2021 09:24:54 +0000 Subject: [PATCH 3/3] Fixed several code style problems --- lib/scsi-lowlevel.c | 6 +++--- test-tool/test_receive_copy_results_copy_status.c | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index fc47b61..4039cea 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -1557,9 +1557,9 @@ scsi_inquiry_unmarshall_third_party_copy(struct scsi_task *task) return NULL; } - inq->qualifier = (task_get_uint8(task, 0) >> 5) & 0x07; - inq->device_type = task_get_uint8(task, 0) & 0x1f; - inq->pagecode = task_get_uint8(task, 1); + inq->qualifier = (task_get_uint8(task, 0) >> 5) & 0x07; + inq->device_type = task_get_uint8(task, 0) & 0x1f; + inq->pagecode = task_get_uint8(task, 1); remaining = task_get_uint16(task, 2); dptr = &task->datain.data[4]; diff --git a/test-tool/test_receive_copy_results_copy_status.c b/test-tool/test_receive_copy_results_copy_status.c index dbefe7e..3cda526 100644 --- a/test-tool/test_receive_copy_results_copy_status.c +++ b/test-tool/test_receive_copy_results_copy_status.c @@ -27,8 +27,6 @@ #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" - - void test_receive_copy_results_copy_status(void) {