From ee5000ba9dd74172284e8416567ff19a698d6b12 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Wed, 2 Jan 2013 17:15:48 -0800 Subject: [PATCH 1/4] Moved support routines from iscsi-test to iscsi-support, in preperation for sharing non-main functions. --- Makefile.am | 1 + test-tool/iscsi-test.c | 20 ++++++++++++++++---- test-tool/iscsi-test.h | 9 +++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index b497e8e..4f8b91d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ dist_noinst_HEADERS += test-tool/iscsi-test.h bin_iscsi_test_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool bin_iscsi_test_LDFLAGS = -ldl bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ + test-tool/iscsi-support.c \ test-tool/0000_testunitready_simple.c \ test-tool/0100_read10_simple.c test-tool/0101_read10_beyond_eol.c \ test-tool/0102_read10_0blocks.c test-tool/0103_read10_rdprotect.c \ diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index 0028216..73da782 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -34,11 +34,18 @@ #include "scsi-lowlevel.h" #include "iscsi-private.h" #include "iscsi-test.h" +#include "iscsi-support.h" #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif + +int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); + + +#ifdef STILL_HERE + const char *initiatorname1 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test"; const char *initiatorname2 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test-2"; @@ -55,12 +62,14 @@ int encserv; int data_loss; int show_info; +#endif /* STILL_HERE */ + struct scsi_test { const char *name; int (*test)(const char *initiator, const char *url); }; -struct scsi_test tests[] = { +static struct scsi_test tests[] = { /* SCSI protocol tests */ /* testunitready*/ @@ -280,14 +289,14 @@ struct scsi_test tests[] = { }; -void print_usage(void) +static void print_usage(void) { fprintf(stderr, "Usage: iscsi-test [-?] [-?|--help] [--usage] [-t|--test=] [-s|--skip=]\n" "\t\t[-l|--list] [--info] [-i|--initiator-name=]\n" "\t\t\n"); } -void print_help(void) +static void print_help(void) { fprintf(stderr, "Usage: iscsi-test [OPTION...] \n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); @@ -311,6 +320,8 @@ void print_help(void) } +#ifdef STILL_HERE + struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun) { struct iscsi_context *iscsi; @@ -397,7 +408,6 @@ void wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_st } } -static int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { @@ -1593,6 +1603,8 @@ int inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int m return 0; } +#endif /* STILL_HERE */ + int main(int argc, const char *argv[]) { diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index 23bb019..422bab2 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -25,6 +25,10 @@ #include #include +#include "iscsi-support.h" + +#ifdef STILL_HERE + extern const char *initiatorname1; extern const char *initiatorname2; @@ -40,13 +44,16 @@ extern enum scsi_inquiry_peripheral_device_type device_type; extern int sccs; extern int encserv; + struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun); +#ifdef STILL_HERE struct iscsi_async_state { struct scsi_task *task; int status; int finished; }; +#endif /* STILL_HERE */ void wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *test_state); struct iscsi_pdu; @@ -289,4 +296,6 @@ int verify16_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *dat int verify16_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); int inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize); +#endif /* STILL_HERE */ + #endif /* _ISCSI_TEST_H_ */ From b8da17b3ec1660acf6e91ac6ef0b57f2bce928b2 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Thu, 3 Jan 2013 19:56:30 -0800 Subject: [PATCH 2/4] Now main() is seperate from guts of testing. --- test-tool/iscsi-support.c | 1379 +++++++++++++++++++++++++++++++++++++ test-tool/iscsi-support.h | 130 ++++ test-tool/iscsi-test.c | 1306 ----------------------------------- test-tool/iscsi-test.h | 107 --- 4 files changed, 1509 insertions(+), 1413 deletions(-) create mode 100644 test-tool/iscsi-support.c create mode 100644 test-tool/iscsi-support.h diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c new file mode 100644 index 0000000..b720ba0 --- /dev/null +++ b/test-tool/iscsi-support.c @@ -0,0 +1,1379 @@ +/* + iscsi-test tool support + + Copyright (C) 2012 by Lee Duncan + + 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 . +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "slist.h" +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-private.h" +#include "iscsi-support.h" + + +const char *initiatorname1 = + "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test"; +const char *initiatorname2 = + "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test-2"; + +uint32_t block_size; +uint64_t num_blocks; +int lbpme; +int lbppb; +int lbpme; +int removable; +enum scsi_inquiry_peripheral_device_type device_type; +int sccs; +int encserv; + +int data_loss; +int show_info; + + +int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); + + +struct iscsi_context * +iscsi_context_login(const char *initiatorname, const char *url, int *lun) +{ + struct iscsi_context *iscsi; + struct iscsi_url *iscsi_url; + + iscsi = iscsi_create_context(initiatorname); + if (iscsi == NULL) { + fprintf(stderr, "Failed to create context\n"); + return NULL; + } + + iscsi_url = iscsi_parse_full_url(iscsi, url); + if (iscsi_url == NULL) { + fprintf(stderr, "Failed to parse URL: %s\n", + iscsi_get_error(iscsi)); + iscsi_destroy_context(iscsi); + return NULL; + } + + iscsi_set_targetname(iscsi, iscsi_url->target); + iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); + + if (iscsi_url->user != NULL) { + if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { + fprintf(stderr, "Failed to set initiator username and password\n"); + iscsi_destroy_url(iscsi_url); + iscsi_destroy_context(iscsi); + return NULL; + } + } + + if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { + fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi)); + iscsi_destroy_url(iscsi_url); + iscsi_destroy_context(iscsi); + return NULL; + } + if (lun != NULL) { + *lun = iscsi_url->lun; + } + + iscsi_destroy_url(iscsi_url); + return iscsi; +} + +void +wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *state) +{ + struct pollfd pfd; + int count = 0; + int ret; + + while (state->finished == 0) { + pfd.fd = iscsi_get_fd(iscsi); + pfd.events = iscsi_which_events(iscsi); + + ret = poll(&pfd, 1, 1000); + if (ret < 0) { + printf("Poll failed"); + exit(10); + } + if (ret == 0) { + if (count++ > 5) { + struct iscsi_pdu *pdu; + + state->finished = 1; + state->status = SCSI_STATUS_CANCELLED; + state->task->status = SCSI_STATUS_CANCELLED; + /* this may leak memory since we dont free the pdu */ + while ((pdu = iscsi->outqueue)) { + SLIST_REMOVE(&iscsi->outqueue, pdu); + } + while ((pdu = iscsi->waitpdu)) { + SLIST_REMOVE(&iscsi->waitpdu, pdu); + } + return; + } + continue; + } + if (iscsi_service(iscsi, pfd.revents) < 0) { + printf("iscsi_service failed with : %s\n", iscsi_get_error(iscsi)); + break; + } + } +} + +int +iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) +{ + if (local_iscsi_queue_pdu != NULL) { + local_iscsi_queue_pdu(iscsi, pdu); + } + return real_iscsi_queue_pdu(iscsi, pdu); +} + +int +register_and_ignore(struct iscsi_context *iscsi, int lun, + unsigned long long sark) +{ + struct scsi_persistent_reserve_out_basic poc; + struct scsi_task *task; + + + /* register our reservation key with the target */ + printf("Send PROUT/REGISTER_AND_IGNORE to register init=%s ... ", + iscsi->initiator_name); + memset(&poc, 0, sizeof (poc)); + poc.service_action_reservation_key = sark; + task = iscsi_persistent_reserve_out_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_REGISTER_AND_IGNORE_EXISTING_KEY, + SCSI_PERSISTENT_RESERVE_SCOPE_LU, 0, &poc); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PROUT command: %s\n", + 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) { + printf("[SKIPPED]\n"); + printf("PROUT Not Supported\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PROUT command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + printf("[OK]\n"); + + return 0; +} + + +int +register_key(struct iscsi_context *iscsi, int lun, + unsigned long long sark, unsigned long long rk) +{ + struct scsi_persistent_reserve_out_basic poc; + struct scsi_task *task; + + + /* register our reservation key with the target */ + printf("Send PROUT/REGISTER to %s init=%s... ", + sark != 0 ? "register" : "unregister", + iscsi->initiator_name); + memset(&poc, 0, sizeof (poc)); + poc.service_action_reservation_key = sark; + poc.reservation_key = rk; + task = iscsi_persistent_reserve_out_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_REGISTER, + SCSI_PERSISTENT_RESERVE_SCOPE_LU, 0, &poc); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PROUT command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PROUT command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + printf("[OK]\n"); + + return 0; +} + + +int +verify_key_presence(struct iscsi_context *iscsi, int lun, + unsigned long long key, int present) +{ + struct scsi_task *task; + const int buf_sz = 16384; + int i; + int key_found; + struct scsi_persistent_reserve_in_read_keys *rk = NULL; + + + printf("Send PRIN/READ_KEYS to verify key %s init=%s... ", + present ? "present" : "absent", + iscsi->initiator_name); + task = iscsi_persistent_reserve_in_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_READ_KEYS, buf_sz); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PRIN command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PRIN command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + rk = scsi_datain_unmarshall(task); + if (rk == NULL) { + printf("failed to unmarshall PRIN/READ_KEYS data. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + + key_found = 0; + for (i = 0; i < rk->num_keys; i++) { + if (rk->keys[i] == key) + key_found = 1; + } + + if ((present && key_found) || + (!present && !key_found)) { + printf("[OK]\n"); + return 0; + } else { + printf("[FAILED]\n"); + if (present) + printf("Key found when none expected\n"); + else + printf("Key not found when expected\n"); + return -1; + } +} + + +int +reregister_key_fails(struct iscsi_context *iscsi, int lun, + unsigned long long sark) +{ + struct scsi_persistent_reserve_out_basic poc; + struct scsi_task *task; + + + printf("Send PROUT/REGISTER to ensure reregister fails init=%s... ", + iscsi->initiator_name); + memset(&poc, 0, sizeof (poc)); + poc.service_action_reservation_key = sark; + task = iscsi_persistent_reserve_out_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_REGISTER, + SCSI_PERSISTENT_RESERVE_SCOPE_LU, + SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE, + &poc); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PROUT command: %s\n", + 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) { + printf("[FAILED]\n"); + printf("PROUT/REGISTER when already registered should fail\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PROUT/REGISTER command: succeeded when it should not have!\n"); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + printf("[OK]\n"); + + return 0; +} + + +int +reserve(struct iscsi_context *iscsi, int lun, + unsigned long long key, enum scsi_persistent_out_type pr_type) +{ + struct scsi_persistent_reserve_out_basic poc; + struct scsi_task *task; + + + /* reserve the target using specified reservation type */ + printf("Send PROUT/RESERVE to reserve, type=%d (%s) init=%s ... ", + pr_type, scsi_pr_type_str(pr_type), + iscsi->initiator_name); + + memset(&poc, 0, sizeof (poc)); + poc.reservation_key = key; + task = iscsi_persistent_reserve_out_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_RESERVE, + SCSI_PERSISTENT_RESERVE_SCOPE_LU, + pr_type, &poc); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PROUT command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PROUT command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + printf("[OK]\n"); + + return 0; +} + + +int +release(struct iscsi_context *iscsi, int lun, + unsigned long long key, enum scsi_persistent_out_type pr_type) +{ + struct scsi_persistent_reserve_out_basic poc; + struct scsi_task *task; + + + /* release the target using specified reservation type */ + printf("Send PROUT/RELEASE to release reservation, type=%d init=%s ... ", + pr_type, iscsi->initiator_name); + + memset(&poc, 0, sizeof (poc)); + poc.reservation_key = key; + task = iscsi_persistent_reserve_out_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_RELEASE, + SCSI_PERSISTENT_RESERVE_SCOPE_LU, + pr_type, &poc); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PROUT command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PROUT command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + printf("[OK]\n"); + + return 0; +} + +int +verify_reserved_as(struct iscsi_context *iscsi, int lun, + unsigned long long key, enum scsi_persistent_out_type pr_type) +{ + struct scsi_task *task; + const int buf_sz = 16384; + struct scsi_persistent_reserve_in_read_reservation *rr = NULL; + + + printf("Send PRIN/READ_RESERVATION to verify type=%d init=%s... ", + pr_type, iscsi->initiator_name); + task = iscsi_persistent_reserve_in_sync(iscsi, lun, + SCSI_PERSISTENT_RESERVE_READ_RESERVATION, buf_sz); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PRIN command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PRIN command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + rr = scsi_datain_unmarshall(task); + if (rr == NULL) { + printf("failed to unmarshall PRIN/READ_RESERVATION data. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + scsi_free_scsi_task(task); + + + if (!rr->reserved) { + printf("[FAILED]\n"); + printf("Failed to find Target reserved as expected.\n"); + return -1; + } + if (rr->reservation_key != key) { + printf("[FAILED]\n"); + printf("Failed to find reservation key 0x%llx: found 0x%lx.\n", + key, rr->reservation_key); + return -1; + } + if (rr->pr_type != pr_type) { + printf("[FAILED]\n"); + printf("Failed to find reservation type %d: found %d.\n", + pr_type, rr->pr_type); + return -1; + } + + printf("[OK]\n"); + return 0; +} + + +int +verify_read_works(struct iscsi_context *iscsi, int lun, unsigned char *buf) +{ + struct scsi_task *task; + const uint32_t lba = 1; + const int blksize = 512; + const uint32_t datalen = 1 * blksize; + + /* + * try to read the second 512-byte block + */ + + printf("Send READ10 to verify READ works init=%s ... ", + iscsi->initiator_name); + + task = iscsi_read10_sync(iscsi, lun, lba, datalen, blksize, 0, 0, 0, 0, 0); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send READ10 command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("READ10 command: failed with sense: %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + memcpy(buf, task->datain.data, task->datain.size); + scsi_free_scsi_task(task); + + printf("[OK]\n"); + return 0; +} + +int +verify_write_works(struct iscsi_context *iscsi, int lun, unsigned char *buf) +{ + struct scsi_task *task; + const uint32_t lba = 1; + const int blksize = 512; + const uint32_t datalen = 1 * blksize; + + /* + * try to write the second 512-byte block + */ + + printf("Send WRITE10 to verify WRITE works init=%s ... ", + iscsi->initiator_name); + + task = iscsi_write10_sync(iscsi, lun, lba, buf, datalen, blksize, 0, 0, 0, 0, 0); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send WRITE10 command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("WRITE10 command: failed with sense: %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + scsi_free_scsi_task(task); + + printf("[OK]\n"); + return 0; +} + + +int +verify_read_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf) +{ + struct scsi_task *task; + const uint32_t lba = 1; + const int blksize = 512; + const uint32_t datalen = 1 * blksize; + + /* + * try to read the second 512-byte block -- should fail + */ + + printf("Send READ10 to verify READ does not work init=%s ... ", + iscsi->initiator_name); + + task = iscsi_read10_sync(iscsi, lun, lba, datalen, blksize, 0, 0, 0, 0, 0); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send READ10 command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + memcpy(buf, task->datain.data, task->datain.size); + printf("[FAILED]\n"); + printf("READ10 command succeeded when expected to fail\n"); + scsi_free_scsi_task(task); + return -1; + } + + /* + * XXX should we verify sense data? + */ + + scsi_free_scsi_task(task); + + printf("[OK]\n"); + return 0; +} + +int +verify_write_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf) +{ + struct scsi_task *task; + const uint32_t lba = 1; + const int blksize = 512; + const uint32_t datalen = 1 * blksize; + + /* + * try to write the second 512-byte block + */ + + printf("Send WRITE10 to verify WRITE does not work init=%s ... ", + iscsi->initiator_name); + + task = iscsi_write10_sync(iscsi, lun, lba, buf, datalen, blksize, 0, 0, 0, 0, 0); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send WRITE10 command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("WRITE10 command: succeeded when exptec to fail\n"); + scsi_free_scsi_task(task); + return -1; + } + + /* + * XXX should we verify sense data? + */ + + scsi_free_scsi_task(task); + + printf("[OK]\n"); + return 0; +} + +int +testunitready(struct iscsi_context *iscsi, int lun) +{ + struct scsi_task *task; + + printf("Send TESTUNITREADY ... "); + task = iscsi_testunitready_sync(iscsi, lun); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send TESTUNITREADY command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("TESTUNITREADY command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + scsi_free_scsi_task(task); + printf("[OK]\n"); + return 0; +} + +int +testunitready_nomedium(struct iscsi_context *iscsi, int lun) +{ + struct scsi_task *task; + + printf("Send TESTUNITREADY (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... "); + task = iscsi_testunitready_sync(iscsi, lun); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send TESTUNITREADY command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_NOT_READY + || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { + printf("[FAILED]\n"); + printf("TESTUNITREADY Should have failed with NOT_READY/MEDIUM_NOT_PRESENT*\n"); + scsi_free_scsi_task(task); + return -1; + } + scsi_free_scsi_task(task); + printf("[OK]\n"); + return 0; +} + +int +testunitready_conflict(struct iscsi_context *iscsi, int lun) +{ + struct scsi_task *task; + + printf("Send TESTUNITREADY (expecting RESERVATION_CONFLICT) ... "); + task = iscsi_testunitready_sync(iscsi, lun); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send TESTUNITREADY command: %s\n", + iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_RESERVATION_CONFLICT) { + printf("[FAILED]\n"); + printf("Expected RESERVATION CONFLICT\n"); + return -1; + } + scsi_free_scsi_task(task); + printf("[OK]\n"); + return 0; +} + +int +prefetch10(struct iscsi_context *iscsi, int lun, uint32_t lba, int num, int immed, int group) +{ + struct scsi_task *task; + + printf("Send PREFETCH10 LBA:%d Count:%d IMEMD:%d GROUP:%d ... ", lba, num, immed, group); + task = iscsi_prefetch10_sync(iscsi, lun, lba, num, immed, group); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PREFETCH10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("PREFETCH10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PREFETCH10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + scsi_free_scsi_task(task); + printf("[OK]\n"); + return 0; +} + +int +prefetch10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, + int num, int immed, int group) +{ + struct scsi_task *task; + + printf("Send PREFETCH10 LBA:%d Count:%d IMEMD:%d GROUP:%d (expecting ILLEGAL_REQUEST/LBA_OUT_OF_RANGE) ... ", lba, num, immed, group); + task = iscsi_prefetch10_sync(iscsi, lun, lba, num, immed, group); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PREFETCH10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("PREFETCH10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST + || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { + printf("[FAILED]\n"); + printf("PREFETCH10 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +prefetch10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, + int num, int immed, int group) +{ + struct scsi_task *task; + + printf("Send PREFETCH10 LBA:%d Count:%d IMEMD:%d GROUP:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, num, immed, group); + task = iscsi_prefetch10_sync(iscsi, lun, lba, num, immed, group); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PREFETCH10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("PREFETCH10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_NOT_READY + || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { + printf("[FAILED]\n"); + printf("PREFETCH10 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +prefetch16(struct iscsi_context *iscsi, int lun, uint64_t lba, int num, + int immed, int group) +{ + struct scsi_task *task; + + printf("Send PREFETCH16 LBA:%" PRIu64 " Count:%d IMEMD:%d GROUP:%d ... ", lba, num, immed, group); + task = iscsi_prefetch16_sync(iscsi, lun, lba, num, immed, group); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PREFETCH16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("PREFETCH16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("PREFETCH16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + scsi_free_scsi_task(task); + printf("[OK]\n"); + return 0; +} + +int +prefetch16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, int num, int immed, int group) +{ + struct scsi_task *task; + + printf("Send PREFETCH16 LBA:%" PRIu64 " Count:%d IMEMD:%d GROUP:%d (expecting ILLEGAL_REQUEST/LBA_OUT_OF_RANGE) ... ", lba, num, immed, group); + task = iscsi_prefetch16_sync(iscsi, lun, lba, num, immed, group); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PREFETCH16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("PREFETCH16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST + || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { + printf("[FAILED]\n"); + printf("PREFETCH16 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +prefetch16_nomedium(struct iscsi_context *iscsi, int lun, uint64_t lba, int num, int immed, int group) +{ + struct scsi_task *task; + + printf("Send PREFETCH16 LBA:%" PRIu64 " Count:%d IMEMD:%d GROUP:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, num, immed, group); + task = iscsi_prefetch16_sync(iscsi, lun, lba, num, immed, group); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send PREFETCH16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("PREFETCH16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_NOT_READY + || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { + printf("[FAILED]\n"); + printf("PREFETCH16 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify10(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify10_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_NOT_READY + || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { + printf("[FAILED]\n"); + printf("VERIFY10 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify10_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting MISCOMPARE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY10 command successful but should have failed with MISCOMPARE\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->sense.key != SCSI_SENSE_MISCOMPARE) { + printf("[FAILED]\n"); + printf("VERIFY10 command returned wrong sense key. MISCOMPARE MISCOMPARE 0x%x expected but got key 0x%x. Sense:%s\n", SCSI_SENSE_MISCOMPARE, task->sense.key, iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify10_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting LBA_OUT_OF_RANGE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY10 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY10 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY10 command successful but should have failed with LBA_OUT_OF_RANGE\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST + || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { + printf("[FAILED]\n"); + printf("VERIFY10 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify12(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY12 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY12 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify12_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY12 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY12 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_NOT_READY + || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { + printf("[FAILED]\n"); + printf("VERIFY12 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify12_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting MISCOMPARE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY12 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY12 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY12 command successful but should have failed with MISCOMPARE\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->sense.key != SCSI_SENSE_MISCOMPARE) { + printf("[FAILED]\n"); + printf("VERIFY12 command returned wrong sense key. MISCOMPARE MISCOMPARE 0x%x expected but got key 0x%x. Sense:%s\n", SCSI_SENSE_MISCOMPARE, task->sense.key, iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify12_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting LBA_OUT_OF_RANGE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY12 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY12 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY12 command successful but should have failed with LBA_OUT_OF_RANGE\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST + || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { + printf("[FAILED]\n"); + printf("VERIFY12 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify16(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify16_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_NOT_READY + || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN + && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { + printf("[FAILED]\n"); + printf("VERIFY16 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify16_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting MISCOMPARE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY16 command successful but should have failed with MISCOMPARE\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->sense.key != SCSI_SENSE_MISCOMPARE) { + printf("[FAILED]\n"); + printf("VERIFY16 command returned wrong sense key. MISCOMPARE MISCOMPARE 0x%x expected but got key 0x%x. Sense:%s\n", SCSI_SENSE_MISCOMPARE, task->sense.key, iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +verify16_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) +{ + struct scsi_task *task; + + printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting LBA_OUT_OF_RANGE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); + task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send VERIFY16 command: %s\n", 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) { + printf("[SKIPPED]\n"); + printf("VERIFY16 is not implemented on target\n"); + scsi_free_scsi_task(task); + return -2; + } + if (task->status == SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("VERIFY16 command successful but should have failed with LBA_OUT_OF_RANGE\n"); + scsi_free_scsi_task(task); + return -1; + } + if (task->status != SCSI_STATUS_CHECK_CONDITION + || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST + || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { + printf("[FAILED]\n"); + printf("VERIFY16 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + +int +inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize) +{ + struct scsi_task *task; + + printf("Send INQUIRY evpd:%d page_code:%d ... ", evpd, page_code); + task = iscsi_inquiry_sync(iscsi, lun, evpd, page_code, maxsize); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send INQUIRY command: %s\n", iscsi_get_error(iscsi)); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("[FAILED]\n"); + printf("INQUIRY command: failed with sense. %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + return -1; + } + + printf("[OK]\n"); + scsi_free_scsi_task(task); + return 0; +} + diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h new file mode 100644 index 0000000..47ca5fa --- /dev/null +++ b/test-tool/iscsi-support.h @@ -0,0 +1,130 @@ +/* + iscsi-test tool support + + Copyright (C) 2012 by Lee Duncan + + 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 . +*/ + +#ifndef _ISCSI_SUPPORT_H_ +#define _ISCSI_SUPPORT_H_ + +#include +#include +#include +#include + +extern const char *initiatorname1; +extern const char *initiatorname2; + +extern uint32_t block_size; +extern uint64_t num_blocks; +extern int lbpme; +extern int lbppb; +extern int lbpme; +extern int data_loss; +extern int show_info; +extern int removable; +extern enum scsi_inquiry_peripheral_device_type device_type; +extern int sccs; +extern int encserv; + + +struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun); + +struct iscsi_async_state { + struct scsi_task *task; + int status; + int finished; +}; +void wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *test_state); + +struct iscsi_pdu; +int (*local_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); + + + +/* + * PGR support + */ + +static inline long rand_key(void) +{ + time_t t; + pid_t p; + unsigned int s; + long l; + + (void)time(&t); + p = getpid(); + s = ((int)p * (t & 0xffff)); + srandom(s); + l = random(); + return l; +} + +static inline int pr_type_is_all_registrants( + enum scsi_persistent_out_type pr_type) +{ + switch (pr_type) { + case SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS: + case SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS: + return 1; + default: + return 0; + } +} + +int register_and_ignore(struct iscsi_context *iscsi, int lun, + unsigned long long key); +int register_key(struct iscsi_context *iscsi, int lun, + unsigned long long sark, unsigned long long rk); +int verify_key_presence(struct iscsi_context *iscsi, int lun, + unsigned long long key, int present); +int reregister_key_fails(struct iscsi_context *iscsi, int lun, + unsigned long long sark); +int reserve(struct iscsi_context *iscsi, int lun, + unsigned long long key, enum scsi_persistent_out_type pr_type); +int release(struct iscsi_context *iscsi, int lun, + unsigned long long key, enum scsi_persistent_out_type pr_type); +int verify_reserved_as(struct iscsi_context *iscsi, int lun, + unsigned long long key, enum scsi_persistent_out_type pr_type); +int verify_read_works(struct iscsi_context *iscsi, int lun, unsigned char *buf); +int verify_write_works(struct iscsi_context *iscsi, int lun, unsigned char *buf); +int verify_read_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf); +int verify_write_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf); +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 prefetch10(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); +int prefetch10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); +int prefetch10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); +int prefetch16(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); +int prefetch16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); +int prefetch16_nomedium(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); +int verify10(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify10_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify10_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify10_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify12(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify12_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify12_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify12_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify16(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify16_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify16_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int verify16_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); +int inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize); + +#endif /* _ISCSI_SUPPORT_H_ */ diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index 73da782..d4f2cd4 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -44,26 +44,6 @@ int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); -#ifdef STILL_HERE - -const char *initiatorname1 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test"; -const char *initiatorname2 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test-2"; - -uint32_t block_size; -uint64_t num_blocks; -int lbpme; -int lbppb; -int lbpme; -int removable; -enum scsi_inquiry_peripheral_device_type device_type; -int sccs; -int encserv; - -int data_loss; -int show_info; - -#endif /* STILL_HERE */ - struct scsi_test { const char *name; int (*test)(const char *initiator, const char *url); @@ -320,1292 +300,6 @@ static void print_help(void) } -#ifdef STILL_HERE - -struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun) -{ - struct iscsi_context *iscsi; - struct iscsi_url *iscsi_url; - - iscsi = iscsi_create_context(initiatorname); - if (iscsi == NULL) { - fprintf(stderr, "Failed to create context\n"); - return NULL; - } - - iscsi_url = iscsi_parse_full_url(iscsi, url); - if (iscsi_url == NULL) { - fprintf(stderr, "Failed to parse URL: %s\n", - iscsi_get_error(iscsi)); - iscsi_destroy_context(iscsi); - return NULL; - } - - iscsi_set_targetname(iscsi, iscsi_url->target); - iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); - iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); - - if (iscsi_url->user != NULL) { - if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { - fprintf(stderr, "Failed to set initiator username and password\n"); - iscsi_destroy_url(iscsi_url); - iscsi_destroy_context(iscsi); - return NULL; - } - } - - if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { - fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi)); - iscsi_destroy_url(iscsi_url); - iscsi_destroy_context(iscsi); - return NULL; - } - if (lun != NULL) { - *lun = iscsi_url->lun; - } - - iscsi_destroy_url(iscsi_url); - return iscsi; -} - -void wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *state) -{ - struct pollfd pfd; - int count = 0; - int ret; - - while (state->finished == 0) { - pfd.fd = iscsi_get_fd(iscsi); - pfd.events = iscsi_which_events(iscsi); - - ret = poll(&pfd, 1, 1000); - if (ret < 0) { - printf("Poll failed"); - exit(10); - } - if (ret == 0) { - if (count++ > 5) { - struct iscsi_pdu *pdu; - - state->finished = 1; - state->status = SCSI_STATUS_CANCELLED; - state->task->status = SCSI_STATUS_CANCELLED; - /* this may leak memory since we dont free the pdu */ - while ((pdu = iscsi->outqueue)) { - SLIST_REMOVE(&iscsi->outqueue, pdu); - } - while ((pdu = iscsi->waitpdu)) { - SLIST_REMOVE(&iscsi->waitpdu, pdu); - } - return; - } - continue; - } - if (iscsi_service(iscsi, pfd.revents) < 0) { - printf("iscsi_service failed with : %s\n", iscsi_get_error(iscsi)); - break; - } - } -} - - -int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) -{ - if (local_iscsi_queue_pdu != NULL) { - local_iscsi_queue_pdu(iscsi, pdu); - } - return real_iscsi_queue_pdu(iscsi, pdu); -} - -int register_and_ignore(struct iscsi_context *iscsi, int lun, - unsigned long long sark) -{ - struct scsi_persistent_reserve_out_basic poc; - struct scsi_task *task; - - - /* register our reservation key with the target */ - printf("Send PROUT/REGISTER_AND_IGNORE to register init=%s ... ", - iscsi->initiator_name); - memset(&poc, 0, sizeof (poc)); - poc.service_action_reservation_key = sark; - task = iscsi_persistent_reserve_out_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_REGISTER_AND_IGNORE_EXISTING_KEY, - SCSI_PERSISTENT_RESERVE_SCOPE_LU, 0, &poc); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PROUT command: %s\n", - 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) { - printf("[SKIPPED]\n"); - printf("PROUT Not Supported\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PROUT command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - printf("[OK]\n"); - - return 0; -} - - -int register_key(struct iscsi_context *iscsi, int lun, - unsigned long long sark, unsigned long long rk) -{ - struct scsi_persistent_reserve_out_basic poc; - struct scsi_task *task; - - - /* register our reservation key with the target */ - printf("Send PROUT/REGISTER to %s init=%s... ", - sark != 0 ? "register" : "unregister", - iscsi->initiator_name); - memset(&poc, 0, sizeof (poc)); - poc.service_action_reservation_key = sark; - poc.reservation_key = rk; - task = iscsi_persistent_reserve_out_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_REGISTER, - SCSI_PERSISTENT_RESERVE_SCOPE_LU, 0, &poc); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PROUT command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PROUT command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - printf("[OK]\n"); - - return 0; -} - - -int verify_key_presence(struct iscsi_context *iscsi, int lun, - unsigned long long key, int present) -{ - struct scsi_task *task; - const int buf_sz = 16384; - int i; - int key_found; - struct scsi_persistent_reserve_in_read_keys *rk = NULL; - - - printf("Send PRIN/READ_KEYS to verify key %s init=%s... ", - present ? "present" : "absent", - iscsi->initiator_name); - task = iscsi_persistent_reserve_in_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_READ_KEYS, buf_sz); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PRIN command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PRIN command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - rk = scsi_datain_unmarshall(task); - if (rk == NULL) { - printf("failed to unmarshall PRIN/READ_KEYS data. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - - key_found = 0; - for (i = 0; i < rk->num_keys; i++) { - if (rk->keys[i] == key) - key_found = 1; - } - - if ((present && key_found) || - (!present && !key_found)) { - printf("[OK]\n"); - return 0; - } else { - printf("[FAILED]\n"); - if (present) - printf("Key found when none expected\n"); - else - printf("Key not found when expected\n"); - return -1; - } -} - - -int reregister_key_fails(struct iscsi_context *iscsi, int lun, - unsigned long long sark) -{ - struct scsi_persistent_reserve_out_basic poc; - struct scsi_task *task; - - - printf("Send PROUT/REGISTER to ensure reregister fails init=%s... ", - iscsi->initiator_name); - memset(&poc, 0, sizeof (poc)); - poc.service_action_reservation_key = sark; - task = iscsi_persistent_reserve_out_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_REGISTER, - SCSI_PERSISTENT_RESERVE_SCOPE_LU, - SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE, - &poc); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PROUT command: %s\n", - 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) { - printf("[FAILED]\n"); - printf("PROUT/REGISTER when already registered should fail\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PROUT/REGISTER command: succeeded when it should not have!\n"); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - printf("[OK]\n"); - - return 0; -} - - -int reserve(struct iscsi_context *iscsi, int lun, - unsigned long long key, enum scsi_persistent_out_type pr_type) -{ - struct scsi_persistent_reserve_out_basic poc; - struct scsi_task *task; - - - /* reserve the target using specified reservation type */ - printf("Send PROUT/RESERVE to reserve, type=%d (%s) init=%s ... ", - pr_type, scsi_pr_type_str(pr_type), - iscsi->initiator_name); - - memset(&poc, 0, sizeof (poc)); - poc.reservation_key = key; - task = iscsi_persistent_reserve_out_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_RESERVE, - SCSI_PERSISTENT_RESERVE_SCOPE_LU, - pr_type, &poc); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PROUT command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PROUT command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - printf("[OK]\n"); - - return 0; -} - - -int release(struct iscsi_context *iscsi, int lun, - unsigned long long key, enum scsi_persistent_out_type pr_type) -{ - struct scsi_persistent_reserve_out_basic poc; - struct scsi_task *task; - - - /* release the target using specified reservation type */ - printf("Send PROUT/RELEASE to release reservation, type=%d init=%s ... ", - pr_type, iscsi->initiator_name); - - memset(&poc, 0, sizeof (poc)); - poc.reservation_key = key; - task = iscsi_persistent_reserve_out_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_RELEASE, - SCSI_PERSISTENT_RESERVE_SCOPE_LU, - pr_type, &poc); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PROUT command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PROUT command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - printf("[OK]\n"); - - return 0; -} - -int verify_reserved_as(struct iscsi_context *iscsi, int lun, - unsigned long long key, enum scsi_persistent_out_type pr_type) -{ - struct scsi_task *task; - const int buf_sz = 16384; - struct scsi_persistent_reserve_in_read_reservation *rr = NULL; - - - printf("Send PRIN/READ_RESERVATION to verify type=%d init=%s... ", - pr_type, iscsi->initiator_name); - task = iscsi_persistent_reserve_in_sync(iscsi, lun, - SCSI_PERSISTENT_RESERVE_READ_RESERVATION, buf_sz); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PRIN command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PRIN command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - rr = scsi_datain_unmarshall(task); - if (rr == NULL) { - printf("failed to unmarshall PRIN/READ_RESERVATION data. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - scsi_free_scsi_task(task); - - - if (!rr->reserved) { - printf("[FAILED]\n"); - printf("Failed to find Target reserved as expected.\n"); - return -1; - } - if (rr->reservation_key != key) { - printf("[FAILED]\n"); - printf("Failed to find reservation key 0x%llx: found 0x%lx.\n", - key, rr->reservation_key); - return -1; - } - if (rr->pr_type != pr_type) { - printf("[FAILED]\n"); - printf("Failed to find reservation type %d: found %d.\n", - pr_type, rr->pr_type); - return -1; - } - - printf("[OK]\n"); - return 0; -} - - -int verify_read_works(struct iscsi_context *iscsi, int lun, unsigned char *buf) -{ - struct scsi_task *task; - const uint32_t lba = 1; - const int blksize = 512; - const uint32_t datalen = 1 * blksize; - - /* - * try to read the second 512-byte block - */ - - printf("Send READ10 to verify READ works init=%s ... ", - iscsi->initiator_name); - - task = iscsi_read10_sync(iscsi, lun, lba, datalen, blksize, 0, 0, 0, 0, 0); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send READ10 command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("READ10 command: failed with sense: %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - memcpy(buf, task->datain.data, task->datain.size); - scsi_free_scsi_task(task); - - printf("[OK]\n"); - return 0; -} - -int verify_write_works(struct iscsi_context *iscsi, int lun, unsigned char *buf) -{ - struct scsi_task *task; - const uint32_t lba = 1; - const int blksize = 512; - const uint32_t datalen = 1 * blksize; - - /* - * try to write the second 512-byte block - */ - - printf("Send WRITE10 to verify WRITE works init=%s ... ", - iscsi->initiator_name); - - task = iscsi_write10_sync(iscsi, lun, lba, buf, datalen, blksize, 0, 0, 0, 0, 0); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send WRITE10 command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("WRITE10 command: failed with sense: %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - scsi_free_scsi_task(task); - - printf("[OK]\n"); - return 0; -} - - -int verify_read_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf) -{ - struct scsi_task *task; - const uint32_t lba = 1; - const int blksize = 512; - const uint32_t datalen = 1 * blksize; - - /* - * try to read the second 512-byte block -- should fail - */ - - printf("Send READ10 to verify READ does not work init=%s ... ", - iscsi->initiator_name); - - task = iscsi_read10_sync(iscsi, lun, lba, datalen, blksize, 0, 0, 0, 0, 0); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send READ10 command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status == SCSI_STATUS_GOOD) { - memcpy(buf, task->datain.data, task->datain.size); - printf("[FAILED]\n"); - printf("READ10 command succeeded when expected to fail\n"); - scsi_free_scsi_task(task); - return -1; - } - - /* - * XXX should we verify sense data? - */ - - scsi_free_scsi_task(task); - - printf("[OK]\n"); - return 0; -} - -int verify_write_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf) -{ - struct scsi_task *task; - const uint32_t lba = 1; - const int blksize = 512; - const uint32_t datalen = 1 * blksize; - - /* - * try to write the second 512-byte block - */ - - printf("Send WRITE10 to verify WRITE does not work init=%s ... ", - iscsi->initiator_name); - - task = iscsi_write10_sync(iscsi, lun, lba, buf, datalen, blksize, 0, 0, 0, 0, 0); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send WRITE10 command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("WRITE10 command: succeeded when exptec to fail\n"); - scsi_free_scsi_task(task); - return -1; - } - - /* - * XXX should we verify sense data? - */ - - scsi_free_scsi_task(task); - - printf("[OK]\n"); - return 0; -} - -int testunitready(struct iscsi_context *iscsi, int lun) -{ - struct scsi_task *task; - - printf("Send TESTUNITREADY ... "); - task = iscsi_testunitready_sync(iscsi, lun); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send TESTUNITREADY command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("TESTUNITREADY command: failed with sense. %s\n", - iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - scsi_free_scsi_task(task); - printf("[OK]\n"); - return 0; -} - -int testunitready_nomedium(struct iscsi_context *iscsi, int lun) -{ - struct scsi_task *task; - - printf("Send TESTUNITREADY (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... "); - task = iscsi_testunitready_sync(iscsi, lun); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send TESTUNITREADY command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_NOT_READY - || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { - printf("[FAILED]\n"); - printf("TESTUNITREADY Should have failed with NOT_READY/MEDIUM_NOT_PRESENT*\n"); - scsi_free_scsi_task(task); - return -1; - } - scsi_free_scsi_task(task); - printf("[OK]\n"); - return 0; -} - -int testunitready_conflict(struct iscsi_context *iscsi, int lun) -{ - struct scsi_task *task; - - printf("Send TESTUNITREADY (expecting RESERVATION_CONFLICT) ... "); - task = iscsi_testunitready_sync(iscsi, lun); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send TESTUNITREADY command: %s\n", - iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_RESERVATION_CONFLICT) { - printf("[FAILED]\n"); - printf("Expected RESERVATION CONFLICT\n"); - return -1; - } - scsi_free_scsi_task(task); - printf("[OK]\n"); - return 0; -} - -int prefetch10(struct iscsi_context *iscsi, int lun, uint32_t lba, int num, int immed, int group) -{ - struct scsi_task *task; - - printf("Send PREFETCH10 LBA:%d Count:%d IMEMD:%d GROUP:%d ... ", lba, num, immed, group); - task = iscsi_prefetch10_sync(iscsi, lun, lba, num, immed, group); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PREFETCH10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("PREFETCH10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PREFETCH10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - scsi_free_scsi_task(task); - printf("[OK]\n"); - return 0; -} - -int prefetch10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, int num, int immed, int group) -{ - struct scsi_task *task; - - printf("Send PREFETCH10 LBA:%d Count:%d IMEMD:%d GROUP:%d (expecting ILLEGAL_REQUEST/LBA_OUT_OF_RANGE) ... ", lba, num, immed, group); - task = iscsi_prefetch10_sync(iscsi, lun, lba, num, immed, group); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PREFETCH10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("PREFETCH10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST - || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { - printf("[FAILED]\n"); - printf("PREFETCH10 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int prefetch10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, int num, int immed, int group) -{ - struct scsi_task *task; - - printf("Send PREFETCH10 LBA:%d Count:%d IMEMD:%d GROUP:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, num, immed, group); - task = iscsi_prefetch10_sync(iscsi, lun, lba, num, immed, group); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PREFETCH10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("PREFETCH10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_NOT_READY - || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { - printf("[FAILED]\n"); - printf("PREFETCH10 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int prefetch16(struct iscsi_context *iscsi, int lun, uint64_t lba, int num, int immed, int group) -{ - struct scsi_task *task; - - printf("Send PREFETCH16 LBA:%" PRIu64 " Count:%d IMEMD:%d GROUP:%d ... ", lba, num, immed, group); - task = iscsi_prefetch16_sync(iscsi, lun, lba, num, immed, group); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PREFETCH16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("PREFETCH16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("PREFETCH16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - scsi_free_scsi_task(task); - printf("[OK]\n"); - return 0; -} - -int prefetch16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, int num, int immed, int group) -{ - struct scsi_task *task; - - printf("Send PREFETCH16 LBA:%" PRIu64 " Count:%d IMEMD:%d GROUP:%d (expecting ILLEGAL_REQUEST/LBA_OUT_OF_RANGE) ... ", lba, num, immed, group); - task = iscsi_prefetch16_sync(iscsi, lun, lba, num, immed, group); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PREFETCH16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("PREFETCH16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST - || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { - printf("[FAILED]\n"); - printf("PREFETCH16 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int prefetch16_nomedium(struct iscsi_context *iscsi, int lun, uint64_t lba, int num, int immed, int group) -{ - struct scsi_task *task; - - printf("Send PREFETCH16 LBA:%" PRIu64 " Count:%d IMEMD:%d GROUP:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, num, immed, group); - task = iscsi_prefetch16_sync(iscsi, lun, lba, num, immed, group); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send PREFETCH16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("PREFETCH16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_NOT_READY - || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { - printf("[FAILED]\n"); - printf("PREFETCH16 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify10(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify10_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_NOT_READY - || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { - printf("[FAILED]\n"); - printf("VERIFY10 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify10_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting MISCOMPARE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY10 command successful but should have failed with MISCOMPARE\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->sense.key != SCSI_SENSE_MISCOMPARE) { - printf("[FAILED]\n"); - printf("VERIFY10 command returned wrong sense key. MISCOMPARE MISCOMPARE 0x%x expected but got key 0x%x. Sense:%s\n", SCSI_SENSE_MISCOMPARE, task->sense.key, iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify10_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY10 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting LBA_OUT_OF_RANGE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify10_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY10 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY10 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY10 command successful but should have failed with LBA_OUT_OF_RANGE\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST - || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { - printf("[FAILED]\n"); - printf("VERIFY10 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify12(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY12 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY12 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY12 command: failed with sense. %s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify12_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY12 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY12 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_NOT_READY - || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { - printf("[FAILED]\n"); - printf("VERIFY12 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify12_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting MISCOMPARE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY12 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY12 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY12 command successful but should have failed with MISCOMPARE\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->sense.key != SCSI_SENSE_MISCOMPARE) { - printf("[FAILED]\n"); - printf("VERIFY12 command returned wrong sense key. MISCOMPARE MISCOMPARE 0x%x expected but got key 0x%x. Sense:%s\n", SCSI_SENSE_MISCOMPARE, task->sense.key, iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify12_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY12 LBA:%d blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting LBA_OUT_OF_RANGE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify12_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY12 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY12 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY12 command successful but should have failed with LBA_OUT_OF_RANGE\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST - || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { - printf("[FAILED]\n"); - printf("VERIFY12 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify16(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify16_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting NOT_READY/MEDIUM_NOT_PRESENT) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_NOT_READY - || (task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN - && task->sense.ascq != SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED)) { - printf("[FAILED]\n"); - printf("VERIFY16 after eject failed with the wrong sense code. Should fail with NOT_READY/MEDIUM_NOT_PRESENT*\n"); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify16_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting MISCOMPARE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY16 command successful but should have failed with MISCOMPARE\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->sense.key != SCSI_SENSE_MISCOMPARE) { - printf("[FAILED]\n"); - printf("VERIFY16 command returned wrong sense key. MISCOMPARE MISCOMPARE 0x%x expected but got key 0x%x. Sense:%s\n", SCSI_SENSE_MISCOMPARE, task->sense.key, iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int verify16_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize) -{ - struct scsi_task *task; - - printf("Send VERIFY16 LBA:%" PRIu64 " blocks:%d vprotect:%d dpo:%d bytchk:%d (expecting LBA_OUT_OF_RANGE) ... ", lba, datalen / blocksize, vprotect, dpo, bytchk); - task = iscsi_verify16_sync(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send VERIFY16 command: %s\n", 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) { - printf("[SKIPPED]\n"); - printf("VERIFY16 is not implemented on target\n"); - scsi_free_scsi_task(task); - return -2; - } - if (task->status == SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("VERIFY16 command successful but should have failed with LBA_OUT_OF_RANGE\n"); - scsi_free_scsi_task(task); - return -1; - } - if (task->status != SCSI_STATUS_CHECK_CONDITION - || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST - || task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) { - printf("[FAILED]\n"); - printf("VERIFY16 should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -int inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize) -{ - struct scsi_task *task; - - printf("Send INQUIRY evpd:%d page_code:%d ... ", evpd, page_code); - task = iscsi_inquiry_sync(iscsi, lun, evpd, page_code, maxsize); - if (task == NULL) { - printf("[FAILED]\n"); - printf("Failed to send INQUIRY command: %s\n", iscsi_get_error(iscsi)); - return -1; - } - if (task->status != SCSI_STATUS_GOOD) { - printf("[FAILED]\n"); - printf("INQUIRY command: failed with sense. %s\n", iscsi_get_error(iscsi)); - scsi_free_scsi_task(task); - return -1; - } - - printf("[OK]\n"); - scsi_free_scsi_task(task); - return 0; -} - -#endif /* STILL_HERE */ - - int main(int argc, const char *argv[]) { poptContext pc; diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index 422bab2..d6cb652 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -27,38 +27,6 @@ #include "iscsi-support.h" -#ifdef STILL_HERE - -extern const char *initiatorname1; -extern const char *initiatorname2; - -extern uint32_t block_size; -extern uint64_t num_blocks; -extern int lbpme; -extern int lbppb; -extern int lbpme; -extern int data_loss; -extern int show_info; -extern int removable; -extern enum scsi_inquiry_peripheral_device_type device_type; -extern int sccs; -extern int encserv; - - -struct iscsi_context *iscsi_context_login(const char *initiatorname, const char *url, int *lun); - -#ifdef STILL_HERE -struct iscsi_async_state { - struct scsi_task *task; - int status; - int finished; -}; -#endif /* STILL_HERE */ -void wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *test_state); - -struct iscsi_pdu; -int (*local_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); - int T0000_testunitready_simple(const char *initiator, const char *url); int T0100_read10_simple(const char *initiator, const char *url); @@ -223,79 +191,4 @@ int T1143_persistent_reserve_access_check_wero(const char *initiator, const char int T1144_persistent_reserve_access_check_eaar(const char *initiator, const char *url); int T1145_persistent_reserve_access_check_wear(const char *initiator, const char *url); - -/* - * PGR support - */ - -static inline long rand_key(void) -{ - time_t t; - pid_t p; - unsigned int s; - long l; - - (void)time(&t); - p = getpid(); - s = ((int)p * (t & 0xffff)); - srandom(s); - l = random(); - return l; -} - -static inline int pr_type_is_all_registrants( - enum scsi_persistent_out_type pr_type) -{ - switch (pr_type) { - case SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS: - case SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS: - return 1; - default: - return 0; - } -} - -int register_and_ignore(struct iscsi_context *iscsi, int lun, - unsigned long long key); -int register_key(struct iscsi_context *iscsi, int lun, - unsigned long long sark, unsigned long long rk); -int verify_key_presence(struct iscsi_context *iscsi, int lun, - unsigned long long key, int present); -int reregister_key_fails(struct iscsi_context *iscsi, int lun, - unsigned long long sark); -int reserve(struct iscsi_context *iscsi, int lun, - unsigned long long key, enum scsi_persistent_out_type pr_type); -int release(struct iscsi_context *iscsi, int lun, - unsigned long long key, enum scsi_persistent_out_type pr_type); -int verify_reserved_as(struct iscsi_context *iscsi, int lun, - unsigned long long key, enum scsi_persistent_out_type pr_type); -int verify_read_works(struct iscsi_context *iscsi, int lun, unsigned char *buf); -int verify_write_works(struct iscsi_context *iscsi, int lun, unsigned char *buf); -int verify_read_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf); -int verify_write_fails(struct iscsi_context *iscsi, int lun, unsigned char *buf); -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 prefetch10(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); -int prefetch10_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); -int prefetch10_nomedium(struct iscsi_context *iscsi, int lun, uint32_t lba, int num_blocks, int immed, int group); -int prefetch16(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); -int prefetch16_lbaoutofrange(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); -int prefetch16_nomedium(struct iscsi_context *iscsi, int lun, uint64_t lba, int num_blocks, int immed, int group); -int verify10(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify10_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify10_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify10_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify12(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify12_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify12_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify12_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify16(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify16_nomedium(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify16_miscompare(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int verify16_lbaoutofrange(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint64_t lba, int vprotect, int dpo, int bytchk, int blocksize); -int inquiry(struct iscsi_context *iscsi, int lun, int evpd, int page_code, int maxsize); - -#endif /* STILL_HERE */ - #endif /* _ISCSI_TEST_H_ */ From fb4724c8136e06f33563bddd503f8698e0e772d3 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Thu, 3 Jan 2013 19:57:09 -0800 Subject: [PATCH 3/4] Added guts of new cunit-based main routine --- Makefile.am | 9 ++ test-tool/iscsi-test-cu.c | 275 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) create mode 100644 test-tool/iscsi-test-cu.c diff --git a/Makefile.am b/Makefile.am index 4f8b91d..4012698 100644 --- a/Makefile.am +++ b/Makefile.am @@ -163,6 +163,15 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ test-tool/1144_persistent_reserve_access_check_eaar.c \ test-tool/1145_persistent_reserve_access_check_wear.c +# libiscsi test tool using cunit + +noinst_PROGRAMS += bin/iscsi-test-cu +# dist_noinst_HEADERS += test-tool/iscsi-test-cu.h +bin_iscsi_test_cu_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool +bin_iscsi_test_cu_LDFLAGS = -ldl +bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ + test-tool/iscsi-support.c + endif # LD_PRELOAD library. diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c new file mode 100644 index 0000000..d035b7d --- /dev/null +++ b/test-tool/iscsi-test-cu.c @@ -0,0 +1,275 @@ +/* + iscsi-test tool + + Copyright (C) 2012 by Lee Duncan + + 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 . +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "slist.h" +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-private.h" +// #include "iscsi-test.h" +#include "iscsi-support.h" + +#ifndef discard_const +#define discard_const(ptr) ((void *)((intptr_t)(ptr))) +#endif + +#define PROG "iscsi-test-cu" + + +int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); + + + +static void +print_usage(void) +{ + fprintf(stderr, + "Usage: %s [-?] [-?|--help] [--usage] [-t|--test=] [-s|--skip=]\n" + "\t\t[-l|--list] [--info] [-i|--initiator-name=]\n" + "\t\t\n", PROG); +} + +static void +print_help(void) +{ + fprintf(stderr,\ +"Usage: %s [OPTIONS] \n" +" -i, --initiator-name=iqn-name Initiatorname to use\n" +" -I, --initiator-name-2=iqn-name Second initiatorname to use\n" +" -t, --test=test-name Which test to run. Default is to run all tests.\n" +" -s, --skip=test-name Which test to skip. Default is to run all tests.\n" +" -l, --list List all tests.\n" +" --info, Print extra info about a test.\n" +" --dataloss Allow destructive tests.\n" +"\n" +"Help options:\n" +" -?, --help Show this help message\n" +" --usage Display brief usage message\n" +"\n" +"iSCSI URL format : %s\n" +"\n" +" is either of:\n" +" \"hostname\" iscsi.example\n" +" \"ipv4-address\" 10.1.1.27\n" +" \"ipv6-address\" [fce0::1]\n", + PROG, ISCSI_URL_SYNTAX); +} + + +int +main(int argc, const char *argv[]) +{ + poptContext pc; + const char **extra_argv; + int extra_argc = 0; + const char *url = NULL; + int show_help = 0, show_usage = 0, list_tests = 0; + int res; + char *testname = NULL; + char *skipname = NULL; + int lun; + struct iscsi_context *iscsi; + struct scsi_task *task; + struct scsi_readcapacity10 *rc10; + struct scsi_readcapacity16 *rc16; + struct scsi_inquiry_standard *inq; + int full_size; + + struct poptOption popt_options[] = { + { "help", '?', POPT_ARG_NONE, + &show_help, 0, "Show this help message", NULL }, + { "usage", 0, POPT_ARG_NONE, + &show_usage, 0, "Display brief usage message", NULL }, + { "list", 'l', POPT_ARG_NONE, + &list_tests, 0, "List all tests", NULL }, + { "initiator-name", 'i', POPT_ARG_STRING, + &initiatorname1, 0, "Initiatorname to use", "iqn-name" }, + { "initiator-name-2", 'I', POPT_ARG_STRING, + &initiatorname2, 0, "Second initiatorname to use for tests using more than one session", "iqn-name" }, + { "test", 't', POPT_ARG_STRING, + &testname, 0, "Which test to run", "testname" }, + { "skip", 's', POPT_ARG_STRING, + &skipname, 0, "Which test to skip", "skipname" }, + { "info", 0, POPT_ARG_NONE, + &show_info, 0, "Show information about the test", "testname" }, + { "dataloss", 0, POPT_ARG_NONE, + &data_loss, 0, "Allow destructuve tests", NULL }, + POPT_TABLEEND + }; + + real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); + + pc = poptGetContext(argv[0], argc, argv, popt_options, + POPT_CONTEXT_POSIXMEHARDER); + if ((res = poptGetNextOpt(pc)) < -1) { + fprintf(stderr, "Failed to parse option : %s %s\n", + poptBadOption(pc, 0), poptStrerror(res)); + return 10; + } + extra_argv = poptGetArgs(pc); + if (extra_argv) { + url = strdup(*extra_argv); + extra_argv++; + while (extra_argv[extra_argc]) { + extra_argc++; + } + } + + if (show_help != 0) { + print_help(); + return 0; + } + + if (show_usage != 0) { + print_usage(); + return 0; + } + + if (list_tests != 0) { + /* + * XXX list tests here ... + */ + return 0; + } + poptFreeContext(pc); + + if (url == NULL) { + fprintf(stderr, "You must specify the URL\n"); + print_usage(); + free(skipname); + free(testname); + return 10; + } + + iscsi = iscsi_context_login(initiatorname1, url, &lun); + if (iscsi == NULL) { + printf("Failed to login to target\n"); + return -1; + } + + /* + * find the size of the LUN + * All devices support readcapacity10 but only some support + * readcapacity16 + */ + task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); + if (task == NULL) { + printf("Failed to send READCAPACITY10 command: %s\n", + iscsi_get_error(iscsi)); + iscsi_destroy_context(iscsi); + return -1; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("READCAPACITY10 command: failed with sense. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + iscsi_destroy_context(iscsi); + return -1; + } + rc10 = scsi_datain_unmarshall(task); + if (rc10 == NULL) { + printf("failed to unmarshall READCAPACITY10 data. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + iscsi_destroy_context(iscsi); + return -1; + } + block_size = rc10->block_size; + num_blocks = rc10->lba; + scsi_free_scsi_task(task); + + task = iscsi_readcapacity16_sync(iscsi, lun); + if (task == NULL) { + printf("Failed to send READCAPACITY16 command: %s\n", + iscsi_get_error(iscsi)); + iscsi_destroy_context(iscsi); + return -1; + } + if (task->status == SCSI_STATUS_GOOD) { + rc16 = scsi_datain_unmarshall(task); + if (rc16 == NULL) { + printf("failed to unmarshall READCAPACITY16 data. %s\n", + iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + iscsi_destroy_context(iscsi); + return -1; + } + block_size = rc16->block_length; + num_blocks = rc16->returned_lba; + lbpme = rc16->lbpme; + lbppb = 1 << rc16->lbppbe; + lbpme = rc16->lbpme; + + scsi_free_scsi_task(task); + } + + + task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); + return -1; + } + full_size = scsi_datain_getfullsize(task); + if (full_size > task->datain.size) { + scsi_free_scsi_task(task); + + /* we need more data for the full list */ + task = iscsi_inquiry_sync(iscsi, lun, 0, 0, full_size); + if (task == NULL) { + printf("Inquiry command failed : %s\n", + iscsi_get_error(iscsi)); + return -1; + } + } + inq = scsi_datain_unmarshall(task); + if (inq == NULL) { + printf("failed to unmarshall inquiry datain blob\n"); + scsi_free_scsi_task(task); + return -1; + } + removable = inq->rmb; + device_type = inq->device_type; + sccs = inq->sccs; + encserv = inq->encserv; + scsi_free_scsi_task(task); + + iscsi_logout_sync(iscsi); + iscsi_destroy_context(iscsi); + + /* + * XXX do tests here + */ + + free(skipname); + free(testname); + free(discard_const(url)); + + return 0; /* XXX 0??? */ +} From d3324decd29f5fec469d0b9285f62c2656bd2034 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Fri, 4 Jan 2013 18:11:36 -0800 Subject: [PATCH 4/4] CUnit tests now working for first 2 suites, but Makefile.am not correct yet. --- Makefile.am | 14 +- test-tool/iscsi-support.c | 7 +- test-tool/iscsi-support.h | 2 +- test-tool/iscsi-test-cu.c | 455 +++++++++++++++++++------- test-tool/iscsi-test-cu.h | 48 +++ test-tool/iscsi-test.c | 2 + test-tool/iscsi-test.h | 4 + test-tool/test_read10_0blocks.c | 73 +++++ test-tool/test_read10_beyond_eol.c | 88 +++++ test-tool/test_read10_flags.c | 131 ++++++++ test-tool/test_read10_invalid.c | 145 ++++++++ test-tool/test_read10_rdprotect.c | 68 ++++ test-tool/test_read10_simple.c | 53 +++ test-tool/test_testunitready_simple.c | 33 ++ 14 files changed, 993 insertions(+), 130 deletions(-) create mode 100644 test-tool/iscsi-test-cu.h create mode 100644 test-tool/test_read10_0blocks.c create mode 100644 test-tool/test_read10_beyond_eol.c create mode 100644 test-tool/test_read10_flags.c create mode 100644 test-tool/test_read10_invalid.c create mode 100644 test-tool/test_read10_rdprotect.c create mode 100644 test-tool/test_read10_simple.c create mode 100644 test-tool/test_testunitready_simple.c diff --git a/Makefile.am b/Makefile.am index 4012698..83047e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -167,10 +167,18 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ noinst_PROGRAMS += bin/iscsi-test-cu # dist_noinst_HEADERS += test-tool/iscsi-test-cu.h -bin_iscsi_test_cu_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool -bin_iscsi_test_cu_LDFLAGS = -ldl +bin_iscsi_test_cu_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool \ + -I/usr/local/include +bin_iscsi_test_cu_LDFLAGS = -ldl -lcunit bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ - test-tool/iscsi-support.c + test-tool/iscsi-support.c \ + test-tool/test_testunitready_simple.c \ + test-tool/test_read10_simple.c \ + test-tool/test_read10_beyond_eol.c \ + test-tool/test_read10_0blocks.c \ + test-tool/test_read10_rdprotect.c \ + test-tool/test_read10_flags.c \ + test-tool/test_read10_invalid.c endif diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index b720ba0..8a402b4 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -36,11 +36,16 @@ #include "iscsi-support.h" +/***************************************************************** + * globals + *****************************************************************/ const char *initiatorname1 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test"; const char *initiatorname2 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test-2"; +const char *tgt_url; + uint32_t block_size; uint64_t num_blocks; int lbpme; @@ -50,9 +55,7 @@ int removable; enum scsi_inquiry_peripheral_device_type device_type; int sccs; int encserv; - int data_loss; -int show_info; int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index 47ca5fa..89daa8f 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -27,6 +27,7 @@ extern const char *initiatorname1; extern const char *initiatorname2; +extern const char *tgt_url; extern uint32_t block_size; extern uint64_t num_blocks; @@ -34,7 +35,6 @@ extern int lbpme; extern int lbppb; extern int lbpme; extern int data_loss; -extern int show_info; extern int removable; extern enum scsi_inquiry_peripheral_device_type device_type; extern int sccs; diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index d035b7d..a34ebc3 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -24,17 +24,22 @@ #include #include #include -#include +#include #include -#include -#include +#include #include -#include "slist.h" + +#include +#include + #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-private.h" -// #include "iscsi-test.h" + #include "iscsi-support.h" +#include "iscsi-test-cu.h" + + #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) @@ -43,133 +48,314 @@ #define PROG "iscsi-test-cu" +/* XXX what is this for? */ int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +/***************************************************************** + * + * list of tests and test suites + * + *****************************************************************/ +static CU_TestInfo tests_testunitready[] = { + { (char *)"testTurSimple", test_testunitready_simple }, + 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 *)"testRead10Invalid", test_read10_invalid }, + CU_TEST_INFO_NULL +}; + +static CU_SuiteInfo suites[] = { + { (char *)"TestTestUnitReady", test_setup, test_teardown, + tests_testunitready }, + { (char *)"TestRead10", test_setup, test_teardown, + tests_read10 }, + CU_SUITE_INFO_NULL +}; + +/* + * globals for test setup and teardown + */ +int tgt_lun; +struct iscsi_context *iscsic; +struct scsi_task *task; + - static void print_usage(void) { fprintf(stderr, - "Usage: %s [-?] [-?|--help] [--usage] [-t|--test=] [-s|--skip=]\n" - "\t\t[-l|--list] [--info] [-i|--initiator-name=]\n" - "\t\t\n", PROG); -} - -static void -print_help(void) -{ - fprintf(stderr,\ -"Usage: %s [OPTIONS] \n" -" -i, --initiator-name=iqn-name Initiatorname to use\n" -" -I, --initiator-name-2=iqn-name Second initiatorname to use\n" -" -t, --test=test-name Which test to run. Default is to run all tests.\n" -" -s, --skip=test-name Which test to skip. Default is to run all tests.\n" -" -l, --list List all tests.\n" -" --info, Print extra info about a test.\n" -" --dataloss Allow destructive tests.\n" -"\n" -"Help options:\n" -" -?, --help Show this help message\n" -" --usage Display brief usage message\n" -"\n" -"iSCSI URL format : %s\n" -"\n" -" is either of:\n" -" \"hostname\" iscsi.example\n" -" \"ipv4-address\" 10.1.1.27\n" -" \"ipv6-address\" [fce0::1]\n", - PROG, ISCSI_URL_SYNTAX); + "Usage: %s [-?|--help] print this message and exit\n", + PROG); + fprintf(stderr, + "or %s [OPTIONS] \n", PROG); + fprintf(stderr, + "Where OPTIONS are from:\n"); + fprintf(stderr, + " -i|--initiator-name=iqn-name Initiatorname to use [%s]\n", + initiatorname1); + fprintf(stderr, + " -I|--initiator-name-2=iqn-name 2nd Initiatorname to use [%s]\n", + initiatorname2); + fprintf(stderr, + " -t|--test=test-name-reg-exp Test(s) to run [ALL] \n"); + fprintf(stderr, + " -l|--list List all tests and exit\n"); + fprintf(stderr, + " -X|--dataloss Allow destructive tests\n"); + fprintf(stderr, + " -g|--ignore Error Action: Ignore test errors [DEFAULT]\n"); + fprintf(stderr, + " -f|--fail Error Action: FAIL if any tests fail\n"); + fprintf(stderr, + " -A|--abort Error Action: ABORT if any tests fail\n"); + fprintf(stderr, + " -s|--silent Test Mode: Silent\n"); + fprintf(stderr, + " -n|--normal Test Mode: Normal\n"); + fprintf(stderr, + " -v|--verbose Test Mode: Verbose [DEFAULT]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, + "Where iSCSI URL format is: %s\n", ISCSI_URL_SYNTAX); + fprintf(stderr, "\n"); + fprintf(stderr, + " is one of:\n"); + fprintf(stderr, + " \"hostname\" e.g. iscsi.example\n"); + fprintf(stderr, + " \"ipv4-address\" e.g. 10.1.1.27\n"); + fprintf(stderr, + " \"ipv6-address\" e.g. [fce0::1]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, + "and is of the form: SUITENAME_RE[.[SUBTESTNAME_RE]]\n"); + fprintf(stderr, "\n"); } int -main(int argc, const char *argv[]) +test_setup(void) { - poptContext pc; - const char **extra_argv; - int extra_argc = 0; - const char *url = NULL; - int show_help = 0, show_usage = 0, list_tests = 0; - int res; - char *testname = NULL; - char *skipname = NULL; + iscsic = iscsi_context_login(initiatorname1, tgt_url, &tgt_lun); + if (iscsic == NULL) { + fprintf(stderr, + "error: Failed to login to target for test set-up\n"); + return 1; + } + task = NULL; + return 0; +} + + +int +test_teardown(void) +{ + if (task) + scsi_free_scsi_task(task); + iscsi_logout_sync(iscsic); + iscsi_destroy_context(iscsic); + return 0; +} + + +static void +list_all_tests(void) +{ + CU_SuiteInfo *sp; + CU_TestInfo *tp; + + for (sp = suites; sp->pName != NULL; sp++) + for (tp = sp->pTests; tp->pName != NULL; tp++) + printf("%s.%s\n", sp->pName, tp->pName); +} + + +static CU_ErrorCode +add_tests(const char *testname_re) +{ + char *suitename_re = NULL; + char *subtestname_re = NULL; + char *cp; + CU_SuiteInfo *sp; + CU_TestInfo *tp; + + + /* if not testname(s) register all tests and return */ + if (!testname_re) + return CU_register_suites(suites); + + /* + * break testname_re into suitename_re and subtestname_re + * + * syntax is: SUITE_RE[.[SUBTEST_RE]] + */ + + /* is there a subtest name? */ + if ((cp = strchr(testname_re, '.')) == NULL) { + suitename_re = strdup(testname_re); + } else { + size_t suitename_sz; + size_t subtestname_sz; + + suitename_sz = cp - testname_re; + suitename_re = malloc(suitename_sz+1); + memset(suitename_re, 0, suitename_sz+1); + strncpy(suitename_re, testname_re, suitename_sz); + + subtestname_sz = strlen(testname_re) - (suitename_sz+1); + if (subtestname_sz) { + subtestname_re = malloc(subtestname_sz+1); + memset(subtestname_re, 0, subtestname_sz+1); + strncpy(subtestname_re, cp+1, subtestname_sz); + } + } + if (!suitename_re) { + fprintf(stderr, "error: can't parse testsuite name: %s\n", + testname_re); + return CUE_NOTEST; + } + + /* + * cycle through the test suites and tests, adding + * ones that match + */ + for (sp = suites; sp->pName != NULL; sp++) { + int suite_added = 0; + CU_pSuite pSuite = NULL; + + if (fnmatch(suitename_re, sp->pName, 0) != 0) + continue; + + for (tp = sp->pTests; tp->pName != NULL; tp++) { + if (subtestname_re) + if (fnmatch(subtestname_re, tp->pName, 0) != 0) + continue; + if (!suite_added) { + suite_added++; + pSuite = CU_add_suite(sp->pName, + sp->pInitFunc, sp->pCleanupFunc); + } + CU_add_test(pSuite, tp->pName, tp->pTestFunc); + } + } + + /* all done -- clean up */ + if (suitename_re) + free(suitename_re); + if (subtestname_re) + free(subtestname_re); + + return CUE_SUCCESS; +} + + +int +main(int argc, char *argv[]) +{ + char *testname_re = NULL; int lun; - struct iscsi_context *iscsi; - struct scsi_task *task; + CU_BasicRunMode mode = CU_BRM_VERBOSE; + CU_ErrorAction error_action = CUEA_IGNORE; + int res; struct scsi_readcapacity10 *rc10; struct scsi_readcapacity16 *rc16; struct scsi_inquiry_standard *inq; int full_size; - - struct poptOption popt_options[] = { - { "help", '?', POPT_ARG_NONE, - &show_help, 0, "Show this help message", NULL }, - { "usage", 0, POPT_ARG_NONE, - &show_usage, 0, "Display brief usage message", NULL }, - { "list", 'l', POPT_ARG_NONE, - &list_tests, 0, "List all tests", NULL }, - { "initiator-name", 'i', POPT_ARG_STRING, - &initiatorname1, 0, "Initiatorname to use", "iqn-name" }, - { "initiator-name-2", 'I', POPT_ARG_STRING, - &initiatorname2, 0, "Second initiatorname to use for tests using more than one session", "iqn-name" }, - { "test", 't', POPT_ARG_STRING, - &testname, 0, "Which test to run", "testname" }, - { "skip", 's', POPT_ARG_STRING, - &skipname, 0, "Which test to skip", "skipname" }, - { "info", 0, POPT_ARG_NONE, - &show_info, 0, "Show information about the test", "testname" }, - { "dataloss", 0, POPT_ARG_NONE, - &data_loss, 0, "Allow destructuve tests", NULL }, - POPT_TABLEEND + static struct option long_opts[] = { + { "help", no_argument, 0, '?' }, + { "list", no_argument, 0, 'l' }, + { "initiator-name", required_argument, 0, 'i' }, + { "initiator-name-2", required_argument, 0, 'I' }, + { "test", required_argument, 0, 't' }, + { "dataloss", no_argument, 0, 'd' }, + { "ignore", no_argument, 0, 'g' }, + { "fail", no_argument, 0, 'f' }, + { "abort", no_argument, 0, 'A' }, + { "silent", no_argument, 0, 's' }, + { "normal", no_argument, 0, 'n' }, + { "verbose", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } }; + int c; + int opt_idx = 0; - real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); - - pc = poptGetContext(argv[0], argc, argv, popt_options, - POPT_CONTEXT_POSIXMEHARDER); - if ((res = poptGetNextOpt(pc)) < -1) { - fprintf(stderr, "Failed to parse option : %s %s\n", - poptBadOption(pc, 0), poptStrerror(res)); - return 10; - } - extra_argv = poptGetArgs(pc); - if (extra_argv) { - url = strdup(*extra_argv); - extra_argv++; - while (extra_argv[extra_argc]) { - extra_argc++; + while ((c = getopt_long(argc, argv, "?hli:I:t:sdgfAsnv", long_opts, + &opt_idx)) > 0) { + switch (c) { + case 'h': + case '?': + print_usage(); + return 0; + case 'l': + list_all_tests(); + return 0; + case 'i': + initiatorname1 = strdup(optarg); + break; + case 'I': + initiatorname2 = strdup(optarg); + break; + case 't': + testname_re = strdup(optarg); + break; + case 'd': + data_loss++; + break; + case 'g': + error_action = CUEA_IGNORE; /* default */ + break; + case 'f': + error_action = CUEA_FAIL; + break; + case 'A': + error_action = CUEA_ABORT; + break; + case 's': + mode = CU_BRM_SILENT; + break; + case 'n': + mode = CU_BRM_NORMAL; + break; + case 'v': + mode = CU_BRM_VERBOSE; /* default */ + break; + default: + fprintf(stderr, + "error: unknown option return: %c (option %s)\n", + c, argv[optind]); + return 1; } } - if (show_help != 0) { - print_help(); - return 0; + if (optind < argc) { + tgt_url = strdup(argv[optind++]); } - - if (show_usage != 0) { + if (optind < argc) { + fprintf(stderr, "error: too many arguments\n"); print_usage(); - return 0; + return 1; } - if (list_tests != 0) { - /* - * XXX list tests here ... - */ - return 0; - } - poptFreeContext(pc); + /* XXX why is this done? */ + real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); - if (url == NULL) { + if (tgt_url == NULL) { fprintf(stderr, "You must specify the URL\n"); print_usage(); - free(skipname); - free(testname); + if (testname_re) + free(testname_re); return 10; } - iscsi = iscsi_context_login(initiatorname1, url, &lun); - if (iscsi == NULL) { + iscsic = iscsi_context_login(initiatorname1, tgt_url, &lun); + if (iscsic == NULL) { printf("Failed to login to target\n"); return -1; } @@ -179,46 +365,46 @@ main(int argc, const char *argv[]) * All devices support readcapacity10 but only some support * readcapacity16 */ - task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); + task = iscsi_readcapacity10_sync(iscsic, lun, 0, 0); if (task == NULL) { printf("Failed to send READCAPACITY10 command: %s\n", - iscsi_get_error(iscsi)); - iscsi_destroy_context(iscsi); + iscsi_get_error(iscsic)); + iscsi_destroy_context(iscsic); return -1; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY10 command: failed with sense. %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); scsi_free_scsi_task(task); - iscsi_destroy_context(iscsi); + iscsi_destroy_context(iscsic); return -1; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); scsi_free_scsi_task(task); - iscsi_destroy_context(iscsi); + iscsi_destroy_context(iscsic); return -1; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); - task = iscsi_readcapacity16_sync(iscsi, lun); + task = iscsi_readcapacity16_sync(iscsic, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", - iscsi_get_error(iscsi)); - iscsi_destroy_context(iscsi); + iscsi_get_error(iscsic)); + iscsi_destroy_context(iscsic); return -1; } if (task->status == SCSI_STATUS_GOOD) { rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); scsi_free_scsi_task(task); - iscsi_destroy_context(iscsi); + iscsi_destroy_context(iscsic); return -1; } block_size = rc16->block_length; @@ -230,10 +416,9 @@ main(int argc, const char *argv[]) scsi_free_scsi_task(task); } - - task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); + task = iscsi_inquiry_sync(iscsic, lun, 0, 0, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { - printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); + printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } full_size = scsi_datain_getfullsize(task); @@ -241,10 +426,10 @@ main(int argc, const char *argv[]) scsi_free_scsi_task(task); /* we need more data for the full list */ - task = iscsi_inquiry_sync(iscsi, lun, 0, 0, full_size); + task = iscsi_inquiry_sync(iscsic, lun, 0, 0, full_size); if (task == NULL) { printf("Inquiry command failed : %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); return -1; } } @@ -260,16 +445,38 @@ main(int argc, const char *argv[]) encserv = inq->encserv; scsi_free_scsi_task(task); - iscsi_logout_sync(iscsi); - iscsi_destroy_context(iscsi); + iscsi_logout_sync(iscsic); + iscsi_destroy_context(iscsic); + + if (CU_initialize_registry() != 0) { + fprintf(stderr, "error: unable to initialize test registry\n"); + return 1; + } + if (CU_is_test_running()) { + fprintf(stderr, "error: test suite(s) already running!?\n"); + exit(1); + } + + if (add_tests(testname_re) != CUE_SUCCESS) { + fprintf(stderr, "error: suite registration failed: %s\n", + CU_get_error_msg()); + exit(1); + } + CU_basic_set_mode(mode); + CU_set_error_action(error_action); + printf("\n"); /* - * XXX do tests here + * this actually runs the tests ... */ + res = CU_basic_run_tests(); - free(skipname); - free(testname); - free(discard_const(url)); + printf("Tests completed with return value: %d\n", res); - return 0; /* XXX 0??? */ + CU_cleanup_registry(); + if (testname_re) + free(testname_re); + free(discard_const(tgt_url)); + + return 0; } diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h new file mode 100644 index 0000000..06d62f9 --- /dev/null +++ b/test-tool/iscsi-test-cu.h @@ -0,0 +1,48 @@ +/* + iscsi-test tool + + Copyright (C) 2012 by Lee Duncan + + 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 . +*/ + +#ifndef _ISCSI_TEST_CU_H_ +#define _ISCSI_TEST_CU_H_ + +#include +#include +#include +#include + +#include "iscsi-support.h" + +/* globals between setup, tests, and teardown */ +extern struct iscsi_context *iscsic; +extern int tgt_lun; +extern struct scsi_task *task; + +int test_setup(void); +int test_teardown(void); + +void test_testunitready_simple(void); + +void test_read10_simple(void); +void test_read10_beyond_eol(void); +void test_read10_0blocks(void); +void test_read10_rdprotect(void); +void test_read10_flags(void); +void test_read10_invalid(void); + + +#endif /* _ISCSI_TEST_CU_H_ */ diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index d4f2cd4..b91b829 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -44,6 +44,8 @@ int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +int show_info; + struct scsi_test { const char *name; int (*test)(const char *initiator, const char *url); diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index d6cb652..a8b85c7 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -27,6 +27,10 @@ #include "iscsi-support.h" + +extern int show_info; + + int T0000_testunitready_simple(const char *initiator, const char *url); int T0100_read10_simple(const char *initiator, const char *url); diff --git a/test-tool/test_read10_0blocks.c b/test-tool/test_read10_0blocks.c new file mode 100644 index 0000000..789f380 --- /dev/null +++ b/test-tool/test_read10_0blocks.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2012 by Lee Duncan + + 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-test-cu.h" + +void +test_read10_0blocks(void) +{ + /* read zero blocks at LBA 0 ... */ + task = iscsi_read10_sync(iscsic, tgt_lun, 0, 0, block_size, + 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* READ10 0blocks at one block beyond ... */ + if (num_blocks > 0x80000000) { + CU_PASS("[SKIPPED] LUN is too big"); + return; + } + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks + 1, 0, + block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + + /* READ10 0blocks at LBA 2^31 ... */ + task = iscsi_read10_sync(iscsic, tgt_lun, 0x80000000, 0, block_size, + 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + + /* READ10 0blocks at LBA -1 ... */ + task = iscsi_read10_sync(iscsic, tgt_lun, -1, 0, block_size, + 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; +} diff --git a/test-tool/test_read10_beyond_eol.c b/test-tool/test_read10_beyond_eol.c new file mode 100644 index 0000000..d8f8188 --- /dev/null +++ b/test-tool/test_read10_beyond_eol.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2012 by Lee Duncan + + 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-test-cu.h" + + +void +test_read10_beyond_eol(void) +{ + int i; + + if (num_blocks >= 0x80000000) { + CU_PASS("LUN is too big for read-beyond-eol tests with READ10. Skipping test.\n"); + return; + } + + /* read 1-256 blocks, one block beyond the end-of-lun */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks + 2 - i, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } + + /* Reading 1-256 blocks at LBA 2^31 */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, 0x80000000, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } + + /* read 1 - 256 blocks at LBA -1 */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, -1, i * block_size, + block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } + + /* read 2-256 blocks, all but one block beyond the eol */ + for (i = 2; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } +} diff --git a/test-tool/test_read10_flags.c b/test-tool/test_read10_flags.c new file mode 100644 index 0000000..d52adce --- /dev/null +++ b/test-tool/test_read10_flags.c @@ -0,0 +1,131 @@ +/* + Copyright (C) 2012 by Lee Duncan + + 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 + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +void +test_read10_flags(void) +{ + struct scsi_task *task_ret; + + + fprintf(stderr, "DEBUG: %s: entering\n", __FUNCTION__); + + /* This test is only valid for SBC devices */ + if (device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + CU_PASS("[SKIPPED] LUN is not SBC device. Skipping test"); + return; + } + + /* Try out READ10 with DPO : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READ10 with FUA : 1 FUA_NV : 0 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x08; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READ10 with FUA : 1 FUA_NV : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x0a; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READ10 with FUA : 0 FUA_NV : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x02; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READM10 with DPO : 1 FUA : 1 FUA_NV : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x18; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; +} diff --git a/test-tool/test_read10_invalid.c b/test-tool/test_read10_invalid.c new file mode 100644 index 0000000..e10cc88 --- /dev/null +++ b/test-tool/test_read10_invalid.c @@ -0,0 +1,145 @@ +/* + Copyright (C) 2012 by Lee Duncan + + 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 + +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + + +void +test_read10_invalid(void) +{ + struct iscsi_data data; + char buf[4096]; + struct scsi_task *task_ret; + + + fprintf(stderr, "DEBUG: %s: entering\n", __FUNCTION__); + + /* Try a read10 of 1 block but xferlength == 0 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = 0; + + /* + * we dont want autoreconnect since some targets will drop the session + * on this condition. + */ + iscsi_set_noautoreconnect(iscsic, 1); + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */ + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size); + scsi_free_scsi_task(task); + task = NULL; + + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(iscsic, 0); + + /* Try a read10 of 1 block but xferlength == 1024 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = 1024; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size); + scsi_free_scsi_task(task); + task = NULL; + + /* Try a read10 of 1 block but xferlength == 200 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = 200; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size - 200); + scsi_free_scsi_task(task); + task = NULL; + + /* Try a read10 of 2 blocks but xferlength == 'block_size' */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 2; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size); + scsi_free_scsi_task(task); + task = NULL; + + /* Try a read10 of 1 block but make it a data-out write on the iscsi layer */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_WRITE; + task->expxferlen = sizeof(buf); + + data.size = sizeof(buf); + data.data = (unsigned char *)&buf[0]; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, &data); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; +} diff --git a/test-tool/test_read10_rdprotect.c b/test-tool/test_read10_rdprotect.c new file mode 100644 index 0000000..f72db9c --- /dev/null +++ b/test-tool/test_read10_rdprotect.c @@ -0,0 +1,68 @@ +/* + Copyright (C) 2012 by Lee Duncan + + 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 + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +void +test_read10_rdprotect(void) +{ + int i; + + + if (device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + CU_PASS("[SKIPPED] LUN is not SBC device. Skipping test"); + return; + } + + /* + * Try out Different non-zero values for RDPROTECT. + * They should all fail. + */ + + /* Read10 with non-zero RDPROTECT ... */ + for (i = 1; i < 8; i++) { + struct scsi_task *task_ret; + + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = (i<<5)&0xe0; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB); + scsi_free_scsi_task(task); + task = NULL; + } +} diff --git a/test-tool/test_read10_simple.c b/test-tool/test_read10_simple.c new file mode 100644 index 0000000..66dddf1 --- /dev/null +++ b/test-tool/test_read10_simple.c @@ -0,0 +1,53 @@ + +/* + Copyright (C) 2012 by Lee Duncan + + 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-test-cu.h" + + +void +test_read10_simple(void) +{ + int i; + + + /* read the first 1 - 256 blocks at the start of the LUN */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, 0, i * block_size, + block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + } + + /* read the last 1 - 256 blocks at the end of the LUN */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks +1 - i, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + } +} diff --git a/test-tool/test_testunitready_simple.c b/test-tool/test_testunitready_simple.c new file mode 100644 index 0000000..e223d18 --- /dev/null +++ b/test-tool/test_testunitready_simple.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2012 by Lee Duncan + + 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-test-cu.h" + +void +test_testunitready_simple(void) +{ + int ret; + + ret = testunitready(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); +}