From 02010f9157f4c5706982de7419885333d9564dbb Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 18 Feb 2013 19:28:53 -0800 Subject: [PATCH] TESTS: Add tests that medium changing commands fail for readonly devices --- Makefile.am | 1 + test-tool/iscsi-support.c | 289 +++++++++++++++++++++++++++++++++- test-tool/iscsi-support.h | 19 ++- test-tool/iscsi-test-cu.c | 92 +++++++---- test-tool/iscsi-test-cu.h | 2 + test-tool/test_readonly_sbc.c | 117 ++++++++++++++ 6 files changed, 487 insertions(+), 33 deletions(-) create mode 100644 test-tool/test_readonly_sbc.c diff --git a/Makefile.am b/Makefile.am index db64c4c..2b2341d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -214,6 +214,7 @@ bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ test-tool/test_readcapacity10_simple.c \ test-tool/test_readcapacity16_simple.c \ test-tool/test_readcapacity16_alloclen.c \ + test-tool/test_readonly_sbc.c \ test-tool/test_testunitready_simple.c \ test-tool/test_unmap_simple.c \ test-tool/test_unmap_0blocks.c \ diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 32f7e27..388521d 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -60,7 +60,7 @@ int data_loss; int lbpws10; int lbpws; int anc_sup; - +int readonly; int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); @@ -1759,6 +1759,47 @@ unmap(struct iscsi_context *iscsi, int lun, int anchor, struct unmap_list *list, return 0; } +int +unmap_writeprotected(struct iscsi_context *iscsi, int lun, int anchor, struct unmap_list *list, int list_len) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send UNMAP (Expecting WRITE_PROTECTED) list_len:%d anchor:%d", list_len, anchor); + task = iscsi_unmap_sync(iscsi, lun, anchor, 0, list, list_len); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send UNMAP command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_CHECK_CONDITION + && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST + && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { + logging(LOG_NORMAL, "[SKIPPED] UNMAP is not implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] UNMAP successful but should " + "have failed with DATA_PROTECTION/WRITE_PROTECTED"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_DATA_PROTECTION + || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { + logging(LOG_NORMAL, "[FAILED] UNMAP failed with wrong sense. " + "Should have failed with DATA_PRTOTECTION/" + "WRITE_PROTECTED. Sense:%s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] UNMAP returned DATA_PROTECTION/WRITE_PROTECTED."); + return 0; +} + int verify10(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int vprotect, int dpo, int bytchk, unsigned char *data) { @@ -2426,6 +2467,54 @@ write10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, return 0; } +int +write10_writeprotected(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, int wrprotect, + int dpo, int fua, int fua_nv, int group, + unsigned char *data) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send WRITE10 (Expecting WRITE_PROTECTED) " + "LBA:%d blocks:%d wrprotect:%d " + "dpo:%d fua:%d fua_nv:%d group:%d", + lba, datalen / blocksize, wrprotect, + dpo, fua, fua_nv, group); + + if (!data_loss) { + printf("--dataloss flag is not set in. Skipping write\n"); + return -1; + } + + task = iscsi_write10_sync(iscsi, lun, lba, data, datalen, blocksize, + wrprotect, dpo, fua, fua_nv, group); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send WRITE10 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] WRITE10 successful but should " + "have failed with DATA_PROTECTION/WRITE_PROTECTED"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_DATA_PROTECTION + || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { + logging(LOG_NORMAL, "[FAILED] WRITE10 failed with wrong sense. " + "Should have failed with DATA_PRTOTECTION/" + "WRITE_PROTECTED. Sense:%s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] WRITE10 returned DATA_PROTECTION/WRITE_PROTECTED."); + return 0; +} + int write12(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, @@ -2559,6 +2648,54 @@ write12_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, return 0; } +int +write12_writeprotected(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, int wrprotect, + int dpo, int fua, int fua_nv, int group, + unsigned char *data) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send WRITE12 (Expecting WRITE_PROTECTED) " + "LBA:%d blocks:%d wrprotect:%d " + "dpo:%d fua:%d fua_nv:%d group:%d", + lba, datalen / blocksize, wrprotect, + dpo, fua, fua_nv, group); + + if (!data_loss) { + printf("--dataloss flag is not set in. Skipping write\n"); + return -1; + } + + task = iscsi_write12_sync(iscsi, lun, lba, data, datalen, blocksize, + wrprotect, dpo, fua, fua_nv, group); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send WRITE12 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] WRITE12 successful but should " + "have failed with DATA_PROTECTION/WRITE_PROTECTED"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_DATA_PROTECTION + || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { + logging(LOG_NORMAL, "[FAILED] WRITE12 failed with wrong sense. " + "Should have failed with DATA_PRTOTECTION/" + "WRITE_PROTECTED. Sense:%s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] WRITE12 returned DATA_PROTECTION/WRITE_PROTECTED."); + return 0; +} + int write16(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int wrprotect, @@ -2692,6 +2829,54 @@ write16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, return 0; } +int +write16_writeprotected(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, int wrprotect, + int dpo, int fua, int fua_nv, int group, + unsigned char *data) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send WRITE16 (Expecting WRITE_PROTECTED) " + "LBA:%" PRIu64 " blocks:%d wrprotect:%d " + "dpo:%d fua:%d fua_nv:%d group:%d", + lba, datalen / blocksize, wrprotect, + dpo, fua, fua_nv, group); + + if (!data_loss) { + printf("--dataloss flag is not set in. Skipping write\n"); + return -1; + } + + task = iscsi_write16_sync(iscsi, lun, lba, data, datalen, blocksize, + wrprotect, dpo, fua, fua_nv, group); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send WRITE16 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] WRITE16 successful but should " + "have failed with DATA_PROTECTION/WRITE_PROTECTED"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_DATA_PROTECTION + || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { + logging(LOG_NORMAL, "[FAILED] WRITE16 failed with wrong sense. " + "Should have failed with DATA_PRTOTECTION/" + "WRITE_PROTECTED. Sense:%s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] WRITE16 returned DATA_PROTECTION/WRITE_PROTECTED."); + return 0; +} + int writesame10(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int num, int anchor, int unmap_flag, int wrprotect, int group, unsigned char *data) { @@ -2837,6 +3022,57 @@ writesame10_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint32_t lba return 0; } +int +writesame10_writeprotected(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int num, int anchor, int unmap_flag, int wrprotect, int group, unsigned char *data) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send WRITESAME10 (Expecting WRITE_PROTECTED) LBA:%d blocks:%d " + "wrprotect:%d anchor:%d unmap:%d group:%d", + lba, num, wrprotect, + anchor, unmap_flag, group); + + if (!data_loss) { + printf("--dataloss flag is not set in. Skipping write\n"); + return -1; + } + + task = iscsi_writesame10_sync(iscsi, lun, lba, + data, datalen, num, + anchor, unmap_flag, wrprotect, group); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send WRITESAME10 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_CHECK_CONDITION + && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST + && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { + logging(LOG_NORMAL, "[SKIPPED] WRITESAME10 is not implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] WRITESAME10 successful but should " + "have failed with DATA_PROTECTION/WRITE_PROTECTED"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_DATA_PROTECTION + || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { + logging(LOG_NORMAL, "[FAILED] WRITESAME10 failed with wrong sense. " + "Should have failed with DATA_PROTECTION/" + "WRITE_PROTECTED. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] WRITESAME10 returned DATA_PROTECTION/WRITE_PROTECTED."); + return 0; +} + int writesame16(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int num, int anchor, int unmap_flag, int wrprotect, int group, unsigned char *data) { @@ -2982,6 +3218,57 @@ writesame16_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint64_t lba return 0; } +int +writesame16_writeprotected(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int num, int anchor, int unmap_flag, int wrprotect, int group, unsigned char *data) +{ + struct scsi_task *task; + + logging(LOG_VERBOSE, "Send WRITESAME16 (Expecting WRITE_PROTECTED) " + "LBA:%" PRIu64 " blocks:%d " + "wrprotect:%d anchor:%d unmap:%d group:%d", + lba, num, wrprotect, + anchor, unmap_flag, group); + + if (!data_loss) { + printf("--dataloss flag is not set in. Skipping write\n"); + return -1; + } + + task = iscsi_writesame16_sync(iscsi, lun, lba, + data, datalen, num, + anchor, unmap_flag, wrprotect, group); + if (task == NULL) { + logging(LOG_NORMAL, "[FAILED] Failed to send WRITESAME16 command: %s", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_CHECK_CONDITION + && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST + && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { + logging(LOG_NORMAL, "[SKIPPED] WRITESAME16 is not implemented on target"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + logging(LOG_NORMAL, "[FAILED] WRITESAME16 successful but should " + "have failed with DATA_PROTECTION/WRITE_PROTECTED"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_DATA_PROTECTION + || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { + logging(LOG_NORMAL, "[FAILED] WRITESAME16 failed with wrong sense. " + "Should have failed with DATA_PROTECTION/" + "WRITE_PROTECTED. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + logging(LOG_VERBOSE, "[OK] WRITESAME16 returned DATA_PROTECTION/WRITE_PROTECTED."); + return 0; +} int diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index 3bf5e51..2403826 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -53,6 +53,17 @@ do { \ } \ } while (0); +#define CHECK_FOR_READONLY \ +do { \ + if (!readonly) { \ + logging(LOG_VERBOSE, "[SKIPPED] Logical unit is not " \ + "write-protected. Skipping test."); \ + CU_PASS("[SKIPPED] Logical unit is not write-" \ + "protected. Skipping test"); \ + return; \ + } \ +} while (0); + #define CHECK_FOR_THIN_PROVISIONING \ do { \ if (lbpme == 0) { \ @@ -119,7 +130,7 @@ extern int encserv; extern int lbpws10; extern int lbpws; extern int anc_sup; - +extern int readonly; struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun); @@ -214,6 +225,7 @@ int testunitready(struct iscsi_context *iscsi, int lun); int testunitready_nomedium(struct iscsi_context *iscsi, int lun); int testunitready_conflict(struct iscsi_context *iscsi, int lun); int unmap(struct iscsi_context *iscsi, int lun, int anchor, struct unmap_list *list, int list_len); +int unmap_writeprotected(struct iscsi_context *iscsi, int lun, int anchor, struct unmap_list *list, int list_len); int verify10(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int vprotect, int dpo, int bytchk, unsigned char *data); int verify10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int vprotect, int dpo, int bytchk, unsigned char *data); int verify10_miscompare(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int vprotect, int dpo, int bytchk, unsigned char *data); @@ -232,18 +244,23 @@ int verify16_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint64_t lb int write10(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write10_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); +int write10_writeprotected(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write12(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write12_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write12_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); +int write12_writeprotected(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write16(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write16_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int write16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); +int write16_writeprotected(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group, unsigned char *data); int writesame10(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); int writesame10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); int writesame10_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); +int writesame10_writeprotected(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); int writesame16(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); int writesame16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); int writesame16_invalidfieldincdb(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); +int writesame16_writeprotected(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int num_blocks, int anchor, int unmap, int wrprotect, int group, unsigned char *data); diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index fd0407c..23257e5 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -82,6 +82,36 @@ static CU_TestInfo tests_prefetch16[] = { CU_TEST_INFO_NULL }; +static CU_TestInfo tests_prin_read_keys[] = { + { (char *)"testPrinReadKeysSimple", test_prin_read_keys_simple }, + CU_TEST_INFO_NULL +}; + +static CU_TestInfo tests_prout_register[] = { + { (char *)"testProutRegisterSimple", test_prout_register_simple }, + CU_TEST_INFO_NULL +}; + +static CU_TestInfo tests_prout_reserve[] = { + { (char *)"testProutReserveSimple", test_prout_reserve_simple }, + { (char *)"testProutReserveAccessEA", test_prout_reserve_access_ea }, + { (char *)"testProutReserveAccessWE", test_prout_reserve_access_we }, + { (char *)"testProutReserveAccessEARO", + test_prout_reserve_access_earo }, + { (char *)"testProutReserveAccessWERO", + test_prout_reserve_access_wero }, + { (char *)"testProutReserveAccessEAAR", + test_prout_reserve_access_eaar }, + { (char *)"testProutReserveAccessWEAR", + test_prout_reserve_access_wear }, + CU_TEST_INFO_NULL +}; + +static CU_TestInfo tests_prin_serviceaction_range[] = { + { (char *)"testPrinServiceactionRange", test_prin_serviceaction_range }, + CU_TEST_INFO_NULL +}; + static CU_TestInfo tests_read6[] = { { (char *)"testRead6Simple", test_read6_simple }, { (char *)"testRead6BeyondEol", test_read6_beyond_eol }, @@ -128,6 +158,11 @@ static CU_TestInfo tests_readcapacity16[] = { CU_TEST_INFO_NULL }; +static CU_TestInfo tests_readonly[] = { + { (char *)"testReadOnlySBC", test_readonly_sbc }, + CU_TEST_INFO_NULL +}; + static CU_TestInfo tests_testunitready[] = { { (char *)"testTurSimple", test_testunitready_simple }, CU_TEST_INFO_NULL @@ -221,37 +256,6 @@ static CU_TestInfo tests_writesame16[] = { CU_TEST_INFO_NULL }; -static CU_TestInfo tests_prin_read_keys[] = { - { (char *)"testPrinReadKeysSimple", test_prin_read_keys_simple }, - CU_TEST_INFO_NULL -}; - -static CU_TestInfo tests_prout_register[] = { - { (char *)"testProutRegisterSimple", test_prout_register_simple }, - CU_TEST_INFO_NULL -}; - -static CU_TestInfo tests_prout_reserve[] = { - { (char *)"testProutReserveSimple", test_prout_reserve_simple }, - { (char *)"testProutReserveAccessEA", test_prout_reserve_access_ea }, - { (char *)"testProutReserveAccessWE", test_prout_reserve_access_we }, - { (char *)"testProutReserveAccessEARO", - test_prout_reserve_access_earo }, - { (char *)"testProutReserveAccessWERO", - test_prout_reserve_access_wero }, - { (char *)"testProutReserveAccessEAAR", - test_prout_reserve_access_eaar }, - { (char *)"testProutReserveAccessWEAR", - test_prout_reserve_access_wear }, - CU_TEST_INFO_NULL -}; - -static CU_TestInfo tests_prin_serviceaction_range[] = { - { (char *)"testPrinServiceactionRange", test_prin_serviceaction_range }, - CU_TEST_INFO_NULL -}; - - static CU_SuiteInfo suites[] = { { (char *)"TestGetLBAStatus", test_setup, test_teardown, tests_get_lba_status }, @@ -271,6 +275,8 @@ static CU_SuiteInfo suites[] = { tests_readcapacity10 }, { (char *)"TestReadCapacity16", test_setup, test_teardown, tests_readcapacity16 }, + { (char *)"TestReadOnly", test_setup, test_teardown, + tests_readonly }, { (char *)"TestTestUnitReady", test_setup, test_teardown, tests_testunitready }, { (char *)"TestUnmap", test_setup, test_teardown, @@ -750,6 +756,30 @@ main(int argc, char *argv[]) scsi_free_scsi_task(task); } + + /* check if the device is write protected or not */ + task = iscsi_modesense6_sync(iscsic, lun, 0, SCSI_MODESENSE_PC_CURRENT, + SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, + 0, 255); + if (task == NULL) { + printf("Failed to send MODE_SENSE6 command: %s\n", + iscsi_get_error(iscsic)); + iscsi_destroy_context(iscsic); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + struct scsi_mode_sense *ms; + + ms = scsi_datain_unmarshall(task); + if (ms == NULL) { + printf("failed to unmarshall mode sense datain blob\n"); + scsi_free_scsi_task(task); + return -1; + } + readonly = !!(ms->device_specific_parameter & 0x80); + } + scsi_free_scsi_task(task); + iscsi_logout_sync(iscsic); iscsi_destroy_context(iscsic); diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index 8ee4f1b..b1feca1 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -83,6 +83,8 @@ void test_readcapacity10_simple(void); void test_readcapacity16_simple(void); void test_readcapacity16_alloclen(void); +void test_readonly_sbc(void); + void test_testunitready_simple(void); void test_unmap_simple(void); diff --git a/test-tool/test_readonly_sbc.c b/test-tool/test_readonly_sbc.c new file mode 100644 index 0000000..6a84d27 --- /dev/null +++ b/test-tool/test_readonly_sbc.c @@ -0,0 +1,117 @@ +/* + Copyright (C) 2013 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-support.h" +#include "iscsi-test-cu.h" + + +void +test_readonly_sbc(void) +{ + int ret; + unsigned char buf[4096]; + struct unmap_list list[1]; + + CHECK_FOR_DATALOSS; + CHECK_FOR_READONLY; + CHECK_FOR_SBC; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test that Medium write commands fail for READ-ONLY SBC devices"); + + + logging(LOG_VERBOSE, "Test WRITE10 fails with WRITE_PROTECTED"); + ret = write10_writeprotected(iscsic, tgt_lun, 0, block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Test WRITE12 fails with WRITE_PROTECTED"); + ret = write12_writeprotected(iscsic, tgt_lun, 0, block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Test WRITE16 fails with WRITE_PROTECTED"); + ret = write16_writeprotected(iscsic, tgt_lun, 0, block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Test WRITE_SAME10 fails with WRITE_PROTECTED"); + ret = writesame10_writeprotected(iscsic, tgt_lun, 0, block_size, 1, + 0, 0, 0, 0, buf); + if (ret == -2) { + logging(LOG_VERBOSE, "WRITE_SAME10 not supported on target. Skipped."); + } + CU_ASSERT_NOT_EQUAL(ret, -1); + + + logging(LOG_VERBOSE, "Test WRITE_SAME16 fails with WRITE_PROTECTED"); + ret = writesame16_writeprotected(iscsic, tgt_lun, 0, block_size, 1, + 0, 0, 0, 0, buf); + if (ret == -2) { + logging(LOG_VERBOSE, "WRITE_SAME16 not supported on target. Skipped."); + } + CU_ASSERT_NOT_EQUAL(ret, -1); + + logging(LOG_VERBOSE, "Test WRITE_SAME10 UNMAP fails with WRITE_PROTECTED"); + ret = writesame10_writeprotected(iscsic, tgt_lun, 0, + block_size, 1, + 0, 1, 0, 0, NULL); + if (ret == -2) { + logging(LOG_VERBOSE, "WRITE_SAME10 not supported on target. Skipped."); + } + CU_ASSERT_NOT_EQUAL(ret, -1); + + logging(LOG_VERBOSE, "Test WRITE_SAME16 UNMAP fails with WRITE_PROTECTED"); + ret = writesame16_writeprotected(iscsic, tgt_lun, 0, + block_size, 1, + 0, 1, 0, 0, NULL); + if (ret == -2) { + logging(LOG_VERBOSE, "WRITE_SAME16 not supported on target. Skipped."); + } + CU_ASSERT_NOT_EQUAL(ret, -1); + + logging(LOG_VERBOSE, "Test UNMAP of one physical block fails with WRITE_PROTECTED"); + list[0].lba = 0; + list[0].num = lbppb; + ret = unmap_writeprotected(iscsic, tgt_lun, 0, list, 1); + if (ret == -2) { + logging(LOG_VERBOSE, "UNMAP not supported on target. Skipped."); + } + CU_ASSERT_NOT_EQUAL(ret, -1); + + logging(LOG_VERBOSE, "Test UNMAP of one logical block fails with WRITE_PROTECTED"); + list[0].lba = 0; + list[0].num = 1; + ret = unmap_writeprotected(iscsic, tgt_lun, 0, list, 1); + if (ret == -2) { + logging(LOG_VERBOSE, "UNMAP not supported on target. Skipped."); + } + CU_ASSERT_NOT_EQUAL(ret, -1); + + /* NOT implemented yet */ + logging(LOG_VERBOSE, "Test for WRITEVERIFY10 not implemented yet."); + logging(LOG_VERBOSE, "Test for WRITEVERIFY12 not implemented yet."); + logging(LOG_VERBOSE, "Test for WRITEVERIFY16 not implemented yet."); + logging(LOG_VERBOSE, "Test for COMPAREANDWRITE not implemented yet."); + logging(LOG_VERBOSE, "Test for ORWRITE not implemented yet."); +}