From 4a8d9675416cb13d82b48524cd7fe34771a900a7 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 29 Apr 2013 20:42:33 -0700 Subject: [PATCH] Add support for synchronous command timeout. Default to 0 meaning no timeout. Implement a test for iSCS to test what happens if we send a command with CMDSN being higher than the target allows. In this case we dont strictly know what will happen, just that what should NOT happen is the target responding with success. But we have to be prepared for any kind of failure, including a timeout, scsi sense, or even iscsi reject or session failure. --- Makefile.am | 1 + include/iscsi-private.h | 6 +- include/iscsi.h | 12 +- lib/init.c | 6 + lib/iscsi-command.c | 40 ++++ lib/libiscsi.def | 1 + lib/libiscsi.syms | 1 + lib/socket.c | 9 +- lib/sync.c | 3 +- test-tool/iscsi-support.c | 6 + test-tool/iscsi-test-cu.c | 337 ++++++++++++++------------- test-tool/iscsi-test-cu.h | 2 + test-tool/test_iscsi_cmdsn_invalid.c | 69 ++++++ 13 files changed, 324 insertions(+), 169 deletions(-) create mode 100644 test-tool/test_iscsi_cmdsn_invalid.c diff --git a/Makefile.am b/Makefile.am index 3308d9f..01af7bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -190,6 +190,7 @@ bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ test-tool/test_inquiry_evpd.c \ test-tool/test_inquiry_supported_vpd.c \ test-tool/test_inquiry_mandatory_vpd_sbc.c \ + test-tool/test_iscsi_cmdsn_invalid.c \ test-tool/test_mandatory_sbc.c \ test-tool/test_nomedia_sbc.c \ test-tool/test_orwrite_simple.c \ diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 9345b09..91e5f38 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -131,7 +131,8 @@ struct iscsi_context { int reallocs; int frees; - time_t last_reconnect; + time_t last_reconnect; + int scsi_timeout; }; #define ISCSI_PDU_IMMEDIATE 0x40 @@ -224,6 +225,7 @@ struct iscsi_pdu { struct iscsi_data indata; struct iscsi_scsi_cbdata scsi_cbdata; + time_t scsi_timeout; }; struct iscsi_pdu *iscsi_allocate_pdu(struct iscsi_context *iscsi, @@ -326,6 +328,8 @@ iscsi_serial32_compare(uint32_t s1, uint32_t s2); u_int32_t iscsi_itt_post_increment(struct iscsi_context *iscsi); +void iscsi_timeout_scan(struct iscsi_context *iscsi); + #ifdef __cplusplus } #endif diff --git a/include/iscsi.h b/include/iscsi.h index 98cdf5d..26cef0f 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -70,11 +70,18 @@ EXTERN int iscsi_service(struct iscsi_context *iscsi, int revents); */ EXTERN int iscsi_queue_length(struct iscsi_context *iscsi); +/* + * Set the timeout in seconds after which a synchronous SCSI command + * will timeout. + * Default is 0 == no timeout. + */ +EXTERN int iscsi_set_timeout(struct iscsi_context *iscsi, int timeout); + /* * To set tcp keepalive for the session. * Only options supported by given platform (if any) are set. */ -int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval); +EXTERN int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval); struct iscsi_url { char portal[MAX_STRING_SIZE+1]; @@ -268,7 +275,8 @@ enum scsi_status { SCSI_STATUS_RESERVATION_CONFLICT = 0x18, SCSI_STATUS_REDIRECT = 0x101, SCSI_STATUS_CANCELLED = 0x0f000000, - SCSI_STATUS_ERROR = 0x0f000001 + SCSI_STATUS_ERROR = 0x0f000001, + SCSI_STATUS_TIMEOUT = 0x0f000002 }; diff --git a/lib/init.c b/lib/init.c index beebd4f..18f3fb2 100644 --- a/lib/init.c +++ b/lib/init.c @@ -534,3 +534,9 @@ iscsi_set_initial_r2t(struct iscsi_context *iscsi, enum iscsi_initial_r2t initia return 0; } +int +iscsi_set_timeout(struct iscsi_context *iscsi, int timeout) +{ + iscsi->scsi_timeout = timeout; + return 0; +} diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 0fdd143..94505d7 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -148,6 +148,45 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, return 0; } +void +iscsi_timeout_scan(struct iscsi_context *iscsi) +{ + struct iscsi_pdu *pdu; + struct iscsi_pdu *next_pdu; + time_t t = time(NULL); + + for (pdu = iscsi->waitpdu; pdu; pdu = next_pdu) { + struct iscsi_scsi_cbdata *scsi_cbdata; + struct scsi_task *task; + + next_pdu = pdu->next; + + if (pdu->scsi_timeout == 0) { + /* no timeout for this pdu */ + continue; + } + if (t < pdu->scsi_timeout) { + /* not expired yet */ + continue; + } + if (pdu->outdata.data[0] != ISCSI_PDU_SCSI_REQUEST) { + continue; + } + + scsi_cbdata = &pdu->scsi_cbdata; + task = scsi_cbdata->task; + + SLIST_REMOVE(&iscsi->waitpdu, pdu); + pdu->callback(iscsi, SCSI_STATUS_TIMEOUT, + task, pdu->private_data); + iscsi_set_error(iscsi, "SCSI command timed out"); + + /* task is freed by the sync caller */ + task->status = SCSI_STATUS_TIMEOUT; + } +} + + /* Using 'struct iscsi_data *d' for data-out is optional * and will be converted into a one element data-out iovector. */ @@ -1662,3 +1701,4 @@ iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi) iscsi_free_pdu(iscsi, pdu); } } + diff --git a/lib/libiscsi.def b/lib/libiscsi.def index b323122..55c5aed 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -63,6 +63,7 @@ iscsi_report_supported_opcodes_task iscsi_reconnect iscsi_set_noautoreconnect iscsi_set_reconnect_max_retries +iscsi_set_timeout iscsi_reportluns_sync iscsi_reportluns_task iscsi_scsi_cancel_all_tasks diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index d087caa..fd01090 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -61,6 +61,7 @@ iscsi_report_supported_opcodes_task iscsi_reconnect iscsi_set_noautoreconnect iscsi_set_reconnect_max_retries +iscsi_set_timeout iscsi_reportluns_sync iscsi_reportluns_task iscsi_scsi_cancel_all_tasks diff --git a/lib/socket.c b/lib/socket.c index 71e1021..a855f92 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -61,6 +61,7 @@ #include #include #include +#include #include "scsi-lowlevel.h" #include "iscsi.h" #include "iscsi-private.h" @@ -73,7 +74,13 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { struct iscsi_pdu *current = iscsi->outqueue; struct iscsi_pdu *last = NULL; - + + if (iscsi->scsi_timeout > 0) { + pdu->scsi_timeout = time(NULL) + iscsi->scsi_timeout; + } else { + pdu->scsi_timeout = 0; + } + if (iscsi->outqueue == NULL) { iscsi->outqueue = pdu; pdu->next = NULL; diff --git a/lib/sync.c b/lib/sync.c index 334efff..3b2bb8c 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "iscsi.h" #include "iscsi-private.h" #include "scsi-lowlevel.h" @@ -60,7 +61,7 @@ event_loop(struct iscsi_context *iscsi, struct iscsi_sync_state *state) return; } if (ret == 0) { - /* poll timedout, try again */ + iscsi_timeout_scan(iscsi); continue; } if (iscsi_service(iscsi, pfd.revents) < 0) { diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 7b587b6..68ef4ee 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -1390,6 +1390,12 @@ testunitready(struct iscsi_context *iscsi, int lun) iscsi_get_error(iscsi)); return -1; } + if (task->status == SCSI_STATUS_TIMEOUT) { + logging(LOG_NORMAL, + "TESTUNITREADY timed out"); + scsi_free_scsi_task(task); + return -1; + } if (task->status != SCSI_STATUS_GOOD) { logging(LOG_NORMAL, "[FAILED] TESTUNITREADY command: failed with sense. %s", diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 8096686..34bfe07 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -61,312 +61,298 @@ int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); * *****************************************************************/ static CU_TestInfo tests_get_lba_status[] = { - { (char *)"testGetLBAStatusSimple", test_get_lba_status_simple }, - { (char *)"testGetLBAStatusBeyondEol", test_get_lba_status_beyond_eol }, + { (char *)"GetLBAStatusSimple", test_get_lba_status_simple }, + { (char *)"GetLBAStatusBeyondEol", test_get_lba_status_beyond_eol }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_inquiry[] = { - { (char *)"testInquiryStandard", test_inquiry_standard }, - { (char *)"testInquiryAllocLength", test_inquiry_alloc_length}, - { (char *)"testInquiryEVPD", test_inquiry_evpd}, - { (char *)"testInquirySupportedVPD", test_inquiry_supported_vpd}, - { (char *)"testInquiryMandatoryVPDSBC", test_inquiry_mandatory_vpd_sbc}, + { (char *)"InquiryStandard", test_inquiry_standard }, + { (char *)"InquiryAllocLength", test_inquiry_alloc_length}, + { (char *)"InquiryEVPD", test_inquiry_evpd}, + { (char *)"InquirySupportedVPD", test_inquiry_supported_vpd}, + { (char *)"InquiryMandatoryVPDSBC", test_inquiry_mandatory_vpd_sbc}, CU_TEST_INFO_NULL }; static CU_TestInfo tests_mandatory[] = { - { (char *)"testMandatorySBC", test_mandatory_sbc }, + { (char *)"MandatorySBC", test_mandatory_sbc }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_nomedia[] = { - { (char *)"testNoMediaSBC", test_nomedia_sbc }, + { (char *)"NoMediaSBC", test_nomedia_sbc }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_orwrite[] = { - { (char *)"testOrWriteSimple", test_orwrite_simple }, - { (char *)"testOrWriteBeyondEol", test_orwrite_beyond_eol }, - { (char *)"testOrWriteZeroBlocks", test_orwrite_0blocks }, - { (char *)"testOrWriteProtect", test_orwrite_wrprotect }, - { (char *)"testOrWriteFlags", test_orwrite_flags }, - { (char *)"testOrWriteVerify", test_orwrite_verify }, + { (char *)"OrWriteSimple", test_orwrite_simple }, + { (char *)"OrWriteBeyondEol", test_orwrite_beyond_eol }, + { (char *)"OrWriteZeroBlocks", test_orwrite_0blocks }, + { (char *)"OrWriteProtect", test_orwrite_wrprotect }, + { (char *)"OrWriteFlags", test_orwrite_flags }, + { (char *)"OrWriteVerify", test_orwrite_verify }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_prefetch10[] = { - { (char *)"testPrefetch10Simple", test_prefetch10_simple }, - { (char *)"testPrefetch10BeyondEol", test_prefetch10_beyond_eol }, - { (char *)"testPrefetch10ZeroBlocks", test_prefetch10_0blocks }, - { (char *)"testPrefetch10Flags", test_prefetch10_flags }, + { (char *)"Prefetch10Simple", test_prefetch10_simple }, + { (char *)"Prefetch10BeyondEol", test_prefetch10_beyond_eol }, + { (char *)"Prefetch10ZeroBlocks", test_prefetch10_0blocks }, + { (char *)"Prefetch10Flags", test_prefetch10_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_prefetch16[] = { - { (char *)"testPrefetch16Simple", test_prefetch16_simple }, - { (char *)"testPrefetch16BeyondEol", test_prefetch16_beyond_eol }, - { (char *)"testPrefetch16ZeroBlocks", test_prefetch16_0blocks }, - { (char *)"testPrefetch16Flags", test_prefetch16_flags }, + { (char *)"Prefetch16Simple", test_prefetch16_simple }, + { (char *)"Prefetch16BeyondEol", test_prefetch16_beyond_eol }, + { (char *)"Prefetch16ZeroBlocks", test_prefetch16_0blocks }, + { (char *)"Prefetch16Flags", test_prefetch16_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_preventallow[] = { - { (char *)"testPreventAllowSimple", test_preventallow_simple }, - { (char *)"testPreventAllowEject", test_preventallow_eject }, - { (char *)"testPreventAllowITNexusLoss", test_preventallow_itnexus_loss }, - { (char *)"testPreventAllowLogout", test_preventallow_logout }, - { (char *)"testPreventAllowWarmReset", test_preventallow_warm_reset }, - { (char *)"testPreventAllowColdReset", test_preventallow_cold_reset }, - { (char *)"testPreventAllowLUNReset", test_preventallow_lun_reset }, - { (char *)"testPreventAllow2ITNexuses", test_preventallow_2_itnexuses }, + { (char *)"PreventAllowSimple", test_preventallow_simple }, + { (char *)"PreventAllowEject", test_preventallow_eject }, + { (char *)"PreventAllowITNexusLoss", test_preventallow_itnexus_loss }, + { (char *)"PreventAllowLogout", test_preventallow_logout }, + { (char *)"PreventAllowWarmReset", test_preventallow_warm_reset }, + { (char *)"PreventAllowColdReset", test_preventallow_cold_reset }, + { (char *)"PreventAllowLUNReset", test_preventallow_lun_reset }, + { (char *)"PreventAllow2ITNexuses", test_preventallow_2_itnexuses }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_prin_read_keys[] = { - { (char *)"testPrinReadKeysSimple", test_prin_read_keys_simple }, + { (char *)"PrinReadKeysSimple", test_prin_read_keys_simple }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_prout_register[] = { - { (char *)"testProutRegisterSimple", test_prout_register_simple }, + { (char *)"ProutRegisterSimple", test_prout_register_simple }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_prout_reserve[] = { - { (char *)"testProutReserveSimple", + { (char *)"ProutReserveSimple", test_prout_reserve_simple }, - { (char *)"testProutReserveAccessEA", + { (char *)"ProutReserveAccessEA", test_prout_reserve_access_ea }, - { (char *)"testProutReserveAccessWE", + { (char *)"ProutReserveAccessWE", test_prout_reserve_access_we }, - { (char *)"testProutReserveAccessEARO", + { (char *)"ProutReserveAccessEARO", test_prout_reserve_access_earo }, - { (char *)"testProutReserveAccessWERO", + { (char *)"ProutReserveAccessWERO", test_prout_reserve_access_wero }, - { (char *)"testProutReserveAccessEAAR", + { (char *)"ProutReserveAccessEAAR", test_prout_reserve_access_eaar }, - { (char *)"testProutReserveAccessWEAR", + { (char *)"ProutReserveAccessWEAR", test_prout_reserve_access_wear }, - { (char *)"testProutReserveOwnershipEA", + { (char *)"ProutReserveOwnershipEA", test_prout_reserve_ownership_ea }, - { (char *)"testProutReserveOwnershipWE", + { (char *)"ProutReserveOwnershipWE", test_prout_reserve_ownership_we }, - { (char *)"testProutReserveOwnershipEARO", + { (char *)"ProutReserveOwnershipEARO", test_prout_reserve_ownership_earo }, - { (char *)"testProutReserveOwnershipWERO", + { (char *)"ProutReserveOwnershipWERO", test_prout_reserve_ownership_wero }, - { (char *)"testProutReserveOwnershipEAAR", + { (char *)"ProutReserveOwnershipEAAR", test_prout_reserve_ownership_eaar }, - { (char *)"testProutReserveOwnershipWEAR", + { (char *)"ProutReserveOwnershipWEAR", test_prout_reserve_ownership_wear }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_prin_serviceaction_range[] = { - { (char *)"testPrinServiceactionRange", test_prin_serviceaction_range }, + { (char *)"PrinServiceactionRange", test_prin_serviceaction_range }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_read6[] = { - { (char *)"testRead6Simple", test_read6_simple }, - { (char *)"testRead6BeyondEol", test_read6_beyond_eol }, - { (char *)"testRead6ZeroBlocks", test_read6_0blocks }, + { (char *)"Read6Simple", test_read6_simple }, + { (char *)"Read6BeyondEol", test_read6_beyond_eol }, + { (char *)"Read6ZeroBlocks", test_read6_0blocks }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_read10[] = { - { (char *)"testRead10Simple", test_read10_simple }, - { (char *)"testRead10BeyondEol", test_read10_beyond_eol }, - { (char *)"testRead10ZeroBlocks", test_read10_0blocks }, - { (char *)"testRead10ReadProtect", test_read10_rdprotect }, - { (char *)"testRead10Flags", test_read10_flags }, + { (char *)"Read10Simple", test_read10_simple }, + { (char *)"Read10BeyondEol", test_read10_beyond_eol }, + { (char *)"Read10ZeroBlocks", test_read10_0blocks }, + { (char *)"Read10ReadProtect", test_read10_rdprotect }, + { (char *)"Read10Flags", test_read10_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_read12[] = { - { (char *)"testRead12Simple", test_read12_simple }, - { (char *)"testRead12BeyondEol", test_read12_beyond_eol }, - { (char *)"testRead12ZeroBlocks", test_read12_0blocks }, - { (char *)"testRead12ReadProtect", test_read12_rdprotect }, - { (char *)"testRead12Flags", test_read12_flags }, + { (char *)"Read12Simple", test_read12_simple }, + { (char *)"Read12BeyondEol", test_read12_beyond_eol }, + { (char *)"Read12ZeroBlocks", test_read12_0blocks }, + { (char *)"Read12ReadProtect", test_read12_rdprotect }, + { (char *)"Read12Flags", test_read12_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_read16[] = { - { (char *)"testRead16Simple", test_read16_simple }, - { (char *)"testRead16BeyondEol", test_read16_beyond_eol }, - { (char *)"testRead16ZeroBlocks", test_read16_0blocks }, - { (char *)"testRead16ReadProtect", test_read16_rdprotect }, - { (char *)"testRead16Flags", test_read16_flags }, + { (char *)"Read16Simple", test_read16_simple }, + { (char *)"Read16BeyondEol", test_read16_beyond_eol }, + { (char *)"Read16ZeroBlocks", test_read16_0blocks }, + { (char *)"Read16ReadProtect", test_read16_rdprotect }, + { (char *)"Read16Flags", test_read16_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_readcapacity10[] = { - { (char *)"testReadCapacity10Simple", test_readcapacity10_simple }, + { (char *)"ReadCapacity10Simple", test_readcapacity10_simple }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_readcapacity16[] = { - { (char *)"testReadCapacity16Simple", test_readcapacity16_simple }, - { (char *)"testReadCapacity16Alloclen", test_readcapacity16_alloclen }, + { (char *)"ReadCapacity16Simple", test_readcapacity16_simple }, + { (char *)"ReadCapacity16Alloclen", test_readcapacity16_alloclen }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_readonly[] = { - { (char *)"testReadOnlySBC", test_readonly_sbc }, + { (char *)"ReadOnlySBC", test_readonly_sbc }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_reserve6[] = { - { (char *)"testReserve6Simple", test_reserve6_simple }, - { (char *)"testReserve6_2Initiators", test_reserve6_2initiators }, - { (char *)"testReserve6Logout", test_reserve6_logout }, - { (char *)"testReserve6ITNexusLoss", test_reserve6_itnexus_loss }, - { (char *)"testReserve6TargetColdReset", test_reserve6_target_cold_reset }, - { (char *)"testReserve6TargetWarmReset", test_reserve6_target_warm_reset }, - { (char *)"testReserve6LUNReset", test_reserve6_lun_reset }, + { (char *)"Reserve6Simple", test_reserve6_simple }, + { (char *)"Reserve6_2Initiators", test_reserve6_2initiators }, + { (char *)"Reserve6Logout", test_reserve6_logout }, + { (char *)"Reserve6ITNexusLoss", test_reserve6_itnexus_loss }, + { (char *)"Reserve6TargetColdReset", test_reserve6_target_cold_reset }, + { (char *)"Reserve6TargetWarmReset", test_reserve6_target_warm_reset }, + { (char *)"Reserve6LUNReset", test_reserve6_lun_reset }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_testunitready[] = { - { (char *)"testTurSimple", test_testunitready_simple }, + { (char *)"TurSimple", test_testunitready_simple }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_startstopunit[] = { - { (char *)"testStartStopUnitSimple", test_startstopunit_simple }, - { (char *)"testStartStopUnitPwrCnd", test_startstopunit_pwrcnd }, - { (char *)"testStartStopUnitNoLoej", test_startstopunit_noloej }, + { (char *)"StartStopUnitSimple", test_startstopunit_simple }, + { (char *)"StartStopUnitPwrCnd", test_startstopunit_pwrcnd }, + { (char *)"StartStopUnitNoLoej", test_startstopunit_noloej }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_unmap[] = { - { (char *)"testUnmapSimple", test_unmap_simple }, - { (char *)"testUnmapZeroBlocks", test_unmap_0blocks }, + { (char *)"UnmapSimple", test_unmap_simple }, + { (char *)"UnmapZeroBlocks", test_unmap_0blocks }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_verify10[] = { - { (char *)"testVerify10Simple", test_verify10_simple }, - { (char *)"testVerify10BeyondEol", test_verify10_beyond_eol }, - { (char *)"testVerify10ZeroBlocks", test_verify10_0blocks }, - { (char *)"testVerify10VerifyProtect", test_verify10_vrprotect }, - { (char *)"testVerify10Flags", test_verify10_flags }, - { (char *)"testVerify10mismatch", test_verify10_mismatch }, - { (char *)"testVerify10mismatch_no_cmp", test_verify10_mismatch_no_cmp }, + { (char *)"Verify10Simple", test_verify10_simple }, + { (char *)"Verify10BeyondEol", test_verify10_beyond_eol }, + { (char *)"Verify10ZeroBlocks", test_verify10_0blocks }, + { (char *)"Verify10VerifyProtect", test_verify10_vrprotect }, + { (char *)"Verify10Flags", test_verify10_flags }, + { (char *)"Verify10mismatch", test_verify10_mismatch }, + { (char *)"Verify10mismatch_no_cmp", test_verify10_mismatch_no_cmp }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_verify12[] = { - { (char *)"testVerify12Simple", test_verify12_simple }, - { (char *)"testVerify12BeyondEol", test_verify12_beyond_eol }, - { (char *)"testVerify12ZeroBlocks", test_verify12_0blocks }, - { (char *)"testVerify12VerifyProtect", test_verify12_vrprotect }, - { (char *)"testVerify12Flags", test_verify12_flags }, - { (char *)"testVerify12mismatch", test_verify12_mismatch }, - { (char *)"testVerify12mismatch_no_cmp", test_verify12_mismatch_no_cmp }, + { (char *)"Verify12Simple", test_verify12_simple }, + { (char *)"Verify12BeyondEol", test_verify12_beyond_eol }, + { (char *)"Verify12ZeroBlocks", test_verify12_0blocks }, + { (char *)"Verify12VerifyProtect", test_verify12_vrprotect }, + { (char *)"Verify12Flags", test_verify12_flags }, + { (char *)"Verify12mismatch", test_verify12_mismatch }, + { (char *)"Verify12mismatch_no_cmp", test_verify12_mismatch_no_cmp }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_verify16[] = { - { (char *)"testVerify16Simple", test_verify16_simple }, - { (char *)"testVerify16BeyondEol", test_verify16_beyond_eol }, - { (char *)"testVerify16ZeroBlocks", test_verify16_0blocks }, - { (char *)"testVerify16VerifyProtect", test_verify16_vrprotect }, - { (char *)"testVerify16Flags", test_verify16_flags }, - { (char *)"testVerify16mismatch", test_verify16_mismatch }, - { (char *)"testVerify16mismatch_no_cmp", test_verify16_mismatch_no_cmp }, + { (char *)"Verify16Simple", test_verify16_simple }, + { (char *)"Verify16BeyondEol", test_verify16_beyond_eol }, + { (char *)"Verify16ZeroBlocks", test_verify16_0blocks }, + { (char *)"Verify16VerifyProtect", test_verify16_vrprotect }, + { (char *)"Verify16Flags", test_verify16_flags }, + { (char *)"Verify16mismatch", test_verify16_mismatch }, + { (char *)"Verify16mismatch_no_cmp", test_verify16_mismatch_no_cmp }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_write10[] = { - { (char *)"testWrite10Simple", test_write10_simple }, - { (char *)"testWrite10BeyondEol", test_write10_beyond_eol }, - { (char *)"testWrite10ZeroBlocks", test_write10_0blocks }, - { (char *)"testWrite10WriteProtect", test_write10_wrprotect }, - { (char *)"testWrite10Flags", test_write10_flags }, + { (char *)"Write10Simple", test_write10_simple }, + { (char *)"Write10BeyondEol", test_write10_beyond_eol }, + { (char *)"Write10ZeroBlocks", test_write10_0blocks }, + { (char *)"Write10WriteProtect", test_write10_wrprotect }, + { (char *)"Write10Flags", test_write10_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_write12[] = { - { (char *)"testWrite12Simple", test_write12_simple }, - { (char *)"testWrite12BeyondEol", test_write12_beyond_eol }, - { (char *)"testWrite12ZeroBlocks", test_write12_0blocks }, - { (char *)"testWrite12WriteProtect", test_write12_wrprotect }, - { (char *)"testWrite12Flags", test_write12_flags }, + { (char *)"Write12Simple", test_write12_simple }, + { (char *)"Write12BeyondEol", test_write12_beyond_eol }, + { (char *)"Write12ZeroBlocks", test_write12_0blocks }, + { (char *)"Write12WriteProtect", test_write12_wrprotect }, + { (char *)"Write12Flags", test_write12_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_write16[] = { - { (char *)"testWrite16Simple", test_write16_simple }, - { (char *)"testWrite16BeyondEol", test_write16_beyond_eol }, - { (char *)"testWrite16ZeroBlocks", test_write16_0blocks }, - { (char *)"testWrite16WriteProtect", test_write16_wrprotect }, - { (char *)"testWrite16Flags", test_write16_flags }, + { (char *)"Write16Simple", test_write16_simple }, + { (char *)"Write16BeyondEol", test_write16_beyond_eol }, + { (char *)"Write16ZeroBlocks", test_write16_0blocks }, + { (char *)"Write16WriteProtect", test_write16_wrprotect }, + { (char *)"Write16Flags", test_write16_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_writesame10[] = { - { (char *)"testWriteSame10Simple", test_writesame10_simple }, - { (char *)"testWriteSame10BeyondEol", test_writesame10_beyond_eol }, - { (char *)"testWriteSame10ZeroBlocks", test_writesame10_0blocks }, - { (char *)"testWriteSame10WriteProtect", test_writesame10_wrprotect }, - { (char *)"testWriteSame10Unmap", test_writesame10_unmap }, - { (char *)"testWriteSame10UnmapUnaligned", test_writesame10_unmap_unaligned }, - { (char *)"testWriteSame10UnmapUntilEnd", test_writesame10_unmap_until_end }, + { (char *)"WriteSame10Simple", test_writesame10_simple }, + { (char *)"WriteSame10BeyondEol", test_writesame10_beyond_eol }, + { (char *)"WriteSame10ZeroBlocks", test_writesame10_0blocks }, + { (char *)"WriteSame10WriteProtect", test_writesame10_wrprotect }, + { (char *)"WriteSame10Unmap", test_writesame10_unmap }, + { (char *)"WriteSame10UnmapUnaligned", test_writesame10_unmap_unaligned }, + { (char *)"WriteSame10UnmapUntilEnd", test_writesame10_unmap_until_end }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_writesame16[] = { - { (char *)"testWriteSame16Simple", test_writesame16_simple }, - { (char *)"testWriteSame16BeyondEol", test_writesame16_beyond_eol }, - { (char *)"testWriteSame16ZeroBlocks", test_writesame16_0blocks }, - { (char *)"testWriteSame16WriteProtect", test_writesame16_wrprotect }, - { (char *)"testWriteSame16Unmap", test_writesame16_unmap }, - { (char *)"testWriteSame16UnmapUnaligned", test_writesame16_unmap_unaligned }, - { (char *)"testWriteSame16UnmapUntilEnd", test_writesame16_unmap_until_end }, + { (char *)"WriteSame16Simple", test_writesame16_simple }, + { (char *)"WriteSame16BeyondEol", test_writesame16_beyond_eol }, + { (char *)"WriteSame16ZeroBlocks", test_writesame16_0blocks }, + { (char *)"WriteSame16WriteProtect", test_writesame16_wrprotect }, + { (char *)"WriteSame16Unmap", test_writesame16_unmap }, + { (char *)"WriteSame16UnmapUnaligned", test_writesame16_unmap_unaligned }, + { (char *)"WriteSame16UnmapUntilEnd", test_writesame16_unmap_until_end }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_writeverify10[] = { - { (char *)"testWriteVerify10Simple", test_writeverify10_simple }, - { (char *)"testWriteVerify10BeyondEol", test_writeverify10_beyond_eol }, - { (char *)"testWriteVerify10ZeroBlocks", test_writeverify10_0blocks }, - { (char *)"testWriteVerify10WriteProtect", test_writeverify10_wrprotect }, - { (char *)"testWriteVerify10Flags", test_writeverify10_flags }, + { (char *)"WriteVerify10Simple", test_writeverify10_simple }, + { (char *)"WriteVerify10BeyondEol", test_writeverify10_beyond_eol }, + { (char *)"WriteVerify10ZeroBlocks", test_writeverify10_0blocks }, + { (char *)"WriteVerify10WriteProtect", test_writeverify10_wrprotect }, + { (char *)"WriteVerify10Flags", test_writeverify10_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_writeverify12[] = { - { (char *)"testWriteVerify12Simple", test_writeverify12_simple }, - { (char *)"testWriteVerify12BeyondEol", test_writeverify12_beyond_eol }, - { (char *)"testWriteVerify12ZeroBlocks", test_writeverify12_0blocks }, - { (char *)"testWriteVerify12WriteProtect", test_writeverify12_wrprotect }, - { (char *)"testWriteVerify12Flags", test_writeverify12_flags }, + { (char *)"WriteVerify12Simple", test_writeverify12_simple }, + { (char *)"WriteVerify12BeyondEol", test_writeverify12_beyond_eol }, + { (char *)"WriteVerify12ZeroBlocks", test_writeverify12_0blocks }, + { (char *)"WriteVerify12WriteProtect", test_writeverify12_wrprotect }, + { (char *)"WriteVerify12Flags", test_writeverify12_flags }, CU_TEST_INFO_NULL }; static CU_TestInfo tests_writeverify16[] = { - { (char *)"testWriteVerify16Simple", test_writeverify16_simple }, - { (char *)"testWriteVerify16BeyondEol", test_writeverify16_beyond_eol }, - { (char *)"testWriteVerify16ZeroBlocks", test_writeverify16_0blocks }, - { (char *)"testWriteVerify16WriteProtect", test_writeverify16_wrprotect }, - { (char *)"testWriteVerify16Flags", test_writeverify16_flags }, - CU_TEST_INFO_NULL -}; - -static CU_TestInfo tests_iscsiresiduals[] = { - { (char *)"testRead10Invalid", test_read10_invalid }, - { (char *)"testRead10Residuals", test_read10_residuals }, - { (char *)"testRead12Residuals", test_read12_residuals }, - { (char *)"testRead16Residuals", test_read16_residuals }, - { (char *)"testWrite10Residuals", test_write10_residuals }, - { (char *)"testWrite12Residuals", test_write12_residuals }, - { (char *)"testWrite16Residuals", test_write16_residuals }, - { (char *)"testWriteVerify10Residuals", test_writeverify10_residuals }, - { (char *)"testWriteVerify12Residuals", test_writeverify12_residuals }, - { (char *)"testWriteVerify16Residuals", test_writeverify16_residuals }, + { (char *)"WriteVerify16Simple", test_writeverify16_simple }, + { (char *)"WriteVerify16BeyondEol", test_writeverify16_beyond_eol }, + { (char *)"WriteVerify16ZeroBlocks", test_writeverify16_0blocks }, + { (char *)"WriteVerify16WriteProtect", test_writeverify16_wrprotect }, + { (char *)"WriteVerify16Flags", test_writeverify16_flags }, CU_TEST_INFO_NULL }; @@ -415,7 +401,7 @@ static CU_SuiteInfo scsi_suites[] = { tests_reserve6 }, { (char *)"StartStopUnit", test_setup, test_teardown, tests_startstopunit }, - { (char *)"TestUnitReady", test_setup, test_teardown, + { (char *)"UnitReady", test_setup, test_teardown, tests_testunitready }, { (char *)"Unmap", test_setup, test_teardown, tests_unmap }, @@ -444,10 +430,31 @@ static CU_SuiteInfo scsi_suites[] = { CU_SUITE_INFO_NULL }; +static CU_TestInfo tests_iscsi_cmdsn[] = { + { (char *)"iSCSICmdSnInvalid", test_iscsi_cmdsn_invalid }, + CU_TEST_INFO_NULL +}; + +static CU_TestInfo tests_iscsi_residuals[] = { + { (char *)"Read10Invalid", test_read10_invalid }, + { (char *)"Read10Residuals", test_read10_residuals }, + { (char *)"Read12Residuals", test_read12_residuals }, + { (char *)"Read16Residuals", test_read16_residuals }, + { (char *)"Write10Residuals", test_write10_residuals }, + { (char *)"Write12Residuals", test_write12_residuals }, + { (char *)"Write16Residuals", test_write16_residuals }, + { (char *)"WriteVerify10Residuals", test_writeverify10_residuals }, + { (char *)"WriteVerify12Residuals", test_writeverify12_residuals }, + { (char *)"WriteVerify16Residuals", test_writeverify16_residuals }, + CU_TEST_INFO_NULL +}; + /* iSCSI protocol tests */ static CU_SuiteInfo iscsi_suites[] = { + { (char *)"iSCSIcmdsn", test_setup, test_teardown, + tests_iscsi_cmdsn }, { (char *)"iSCSIResiduals", test_setup, test_teardown, - tests_iscsiresiduals }, + tests_iscsi_residuals }, CU_SUITE_INFO_NULL }; @@ -521,8 +528,10 @@ static CU_SuiteInfo all_suites[] = { tests_writeverify12 }, { (char *)"WriteVerify16", test_setup, test_teardown, tests_writeverify16 }, + { (char *)"iSCSIcmdsn", test_setup, test_teardown, + tests_iscsi_cmdsn }, { (char *)"iSCSIResiduals", test_setup, test_teardown, - tests_iscsiresiduals }, + tests_iscsi_residuals }, CU_SUITE_INFO_NULL }; diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index 1ef1960..dd5c5cd 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -49,6 +49,8 @@ void test_inquiry_evpd(void); void test_inquiry_supported_vpd(void); void test_inquiry_mandatory_vpd_sbc(void); +void test_iscsi_cmdsn_invalid(void); + void test_mandatory_sbc(void); void test_nomedia_sbc(void); diff --git a/test-tool/test_iscsi_cmdsn_invalid.c b/test-tool/test_iscsi_cmdsn_invalid.c new file mode 100644 index 0000000..faf5fbc --- /dev/null +++ b/test-tool/test_iscsi_cmdsn_invalid.c @@ -0,0 +1,69 @@ +/* + 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 + +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +static int change_cmdsn; + +static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) +{ + switch (change_cmdsn) { + case 1: + /* change the cmdsn so it becomes too big */ + *(uint32_t *)&pdu->outdata.data[24] = htonl(iscsi->maxcmdsn + 1); + break; + case 2: + /* change the cmdsn so it becomes too small */ + *(uint32_t *)&pdu->outdata.data[24] = 0; + break; + } + + change_cmdsn = 0; + return 0; +} + +void test_iscsi_cmdsn_invalid(void) +{ + int ret; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test sending invalid iSCSI CMDSN"); + logging(LOG_VERBOSE, "CMDSN MUST be in the range EXPCMDSN and MAXCMDSN"); + + logging(LOG_VERBOSE, "Test that a CMDSN > MAXCMDSN is an error"); + logging(LOG_VERBOSE, "Send a TESTUNITREADY with CMDSN == MAXCMDSN+1"); + + iscsic->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; + iscsic->target_max_recv_data_segment_length = block_size; + local_iscsi_queue_pdu = my_iscsi_queue_pdu; + change_cmdsn = 1; + /* we dont want autoreconnect since some targets will drop the + * on this condition. + */ + iscsi_set_noautoreconnect(iscsic, 1); + iscsi_set_timeout(iscsic, 3); + + ret = testunitready(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, -1); +}