diff options
Diffstat (limited to 'src/spdk/test/unit/lib/scsi')
-rw-r--r-- | src/spdk/test/unit/lib/scsi/Makefile | 44 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/dev.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/dev.c/Makefile | 40 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/dev.c/dev_ut.c | 681 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/lun.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/lun.c/Makefile | 40 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/lun.c/lun_ut.c | 654 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/scsi.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/scsi.c/Makefile | 41 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/scsi.c/scsi_ut.c | 80 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/scsi_bdev.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/scsi_bdev.c/Makefile | 40 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c | 988 |
13 files changed, 2612 insertions, 0 deletions
diff --git a/src/spdk/test/unit/lib/scsi/Makefile b/src/spdk/test/unit/lib/scsi/Makefile new file mode 100644 index 00000000..9e413897 --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/Makefile @@ -0,0 +1,44 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +DIRS-y = dev.c lun.c scsi.c scsi_bdev.c + +.PHONY: all clean $(DIRS-y) + +all: $(DIRS-y) +clean: $(DIRS-y) + +include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk diff --git a/src/spdk/test/unit/lib/scsi/dev.c/.gitignore b/src/spdk/test/unit/lib/scsi/dev.c/.gitignore new file mode 100644 index 00000000..e325086b --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/dev.c/.gitignore @@ -0,0 +1 @@ +dev_ut diff --git a/src/spdk/test/unit/lib/scsi/dev.c/Makefile b/src/spdk/test/unit/lib/scsi/dev.c/Makefile new file mode 100644 index 00000000..4e7a5fa9 --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/dev.c/Makefile @@ -0,0 +1,40 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +TEST_FILE = dev_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/scsi/dev.c/dev_ut.c b/src/spdk/test/unit/lib/scsi/dev.c/dev_ut.c new file mode 100644 index 00000000..c10a7f0a --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/dev.c/dev_ut.c @@ -0,0 +1,681 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "CUnit/Basic.h" +#include "spdk_cunit.h" + +#include "spdk/util.h" + +#include "scsi/dev.c" +#include "scsi/port.c" + +/* Unit test bdev mockup */ +struct spdk_bdev { + char name[100]; +}; + +static struct spdk_bdev g_bdevs[] = { + {"malloc0"}, + {"malloc1"}, +}; + +const char * +spdk_bdev_get_name(const struct spdk_bdev *bdev) +{ + return bdev->name; +} + +static struct spdk_scsi_task * +spdk_get_task(uint32_t *owner_task_ctr) +{ + struct spdk_scsi_task *task; + + task = calloc(1, sizeof(*task)); + if (!task) { + return NULL; + } + + return task; +} + +void +spdk_scsi_task_put(struct spdk_scsi_task *task) +{ + free(task); +} + +_spdk_scsi_lun * +spdk_scsi_lun_construct(struct spdk_bdev *bdev, + void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), + void *hotremove_ctx) +{ + struct spdk_scsi_lun *lun; + + lun = calloc(1, sizeof(struct spdk_scsi_lun)); + SPDK_CU_ASSERT_FATAL(lun != NULL); + + lun->bdev = bdev; + + return lun; +} + +void +spdk_scsi_lun_destruct(struct spdk_scsi_lun *lun) +{ + free(lun); +} + +struct spdk_bdev * +spdk_bdev_get_by_name(const char *bdev_name) +{ + size_t i; + + for (i = 0; i < SPDK_COUNTOF(g_bdevs); i++) { + if (strcmp(bdev_name, g_bdevs[i].name) == 0) { + return &g_bdevs[i]; + } + } + + return NULL; +} + +int +spdk_scsi_lun_task_mgmt_execute(struct spdk_scsi_task *task, enum spdk_scsi_task_func func) +{ + return 0; +} + +void +spdk_scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) +{ +} + +int +_spdk_scsi_lun_allocate_io_channel(struct spdk_scsi_lun *lun) +{ + return 0; +} + +void +_spdk_scsi_lun_free_io_channel(struct spdk_scsi_lun *lun) +{ +} + +bool +spdk_scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun) +{ + return false; +} + +static void +dev_destruct_null_dev(void) +{ + /* pass null for the dev */ + spdk_scsi_dev_destruct(NULL); +} + +static void +dev_destruct_zero_luns(void) +{ + struct spdk_scsi_dev dev = { .is_allocated = 1 }; + + /* No luns attached to the dev */ + + /* free the dev */ + spdk_scsi_dev_destruct(&dev); +} + +static void +dev_destruct_null_lun(void) +{ + struct spdk_scsi_dev dev = { .is_allocated = 1 }; + + /* pass null for the lun */ + dev.lun[0] = NULL; + + /* free the dev */ + spdk_scsi_dev_destruct(&dev); +} + +static void +dev_destruct_success(void) +{ + struct spdk_scsi_dev dev = { .is_allocated = 1 }; + int rc; + + /* dev with a single lun */ + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", 0, NULL, NULL); + + CU_ASSERT(rc == 0); + + /* free the dev */ + spdk_scsi_dev_destruct(&dev); + +} + +static void +dev_construct_num_luns_zero(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {}; + int lun_id_list[1] = { 0 }; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 0, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* dev should be null since we passed num_luns = 0 */ + CU_ASSERT_TRUE(dev == NULL); +} + +static void +dev_construct_no_lun_zero(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {}; + int lun_id_list[1] = { 0 }; + + lun_id_list[0] = 1; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* dev should be null since no LUN0 was specified (lun_id_list[0] = 1) */ + CU_ASSERT_TRUE(dev == NULL); +} + +static void +dev_construct_null_lun(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {}; + int lun_id_list[1] = { 0 }; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* dev should be null since no LUN0 was specified (lun_list[0] = NULL) */ + CU_ASSERT_TRUE(dev == NULL); +} + +static void +dev_construct_name_too_long(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {"malloc0"}; + int lun_id_list[1] = { 0 }; + char name[SPDK_SCSI_DEV_MAX_NAME + 1 + 1]; + + /* Try to construct a dev with a name that is one byte longer than allowed. */ + memset(name, 'x', sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + + dev = spdk_scsi_dev_construct(name, bdev_name_list, lun_id_list, 1, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + CU_ASSERT(dev == NULL); +} + +static void +dev_construct_success(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {"malloc0"}; + int lun_id_list[1] = { 0 }; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* Successfully constructs and returns a dev */ + CU_ASSERT_TRUE(dev != NULL); + + /* free the dev */ + spdk_scsi_dev_destruct(dev); +} + +static void +dev_construct_success_lun_zero_not_first(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[2] = {"malloc1", "malloc0"}; + int lun_id_list[2] = { 1, 0 }; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 2, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* Successfully constructs and returns a dev */ + CU_ASSERT_TRUE(dev != NULL); + + /* free the dev */ + spdk_scsi_dev_destruct(dev); +} + +static void +dev_queue_mgmt_task_success(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {"malloc0"}; + int lun_id_list[1] = { 0 }; + struct spdk_scsi_task *task; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* Successfully constructs and returns a dev */ + CU_ASSERT_TRUE(dev != NULL); + + task = spdk_get_task(NULL); + + spdk_scsi_dev_queue_mgmt_task(dev, task, SPDK_SCSI_TASK_FUNC_LUN_RESET); + + spdk_scsi_task_put(task); + + spdk_scsi_dev_destruct(dev); +} + +static void +dev_queue_task_success(void) +{ + struct spdk_scsi_dev *dev; + const char *bdev_name_list[1] = {"malloc0"}; + int lun_id_list[1] = { 0 }; + struct spdk_scsi_task *task; + + dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, + SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); + + /* Successfully constructs and returns a dev */ + CU_ASSERT_TRUE(dev != NULL); + + task = spdk_get_task(NULL); + + spdk_scsi_dev_queue_task(dev, task); + + spdk_scsi_task_put(task); + + spdk_scsi_dev_destruct(dev); +} + +static void +dev_stop_success(void) +{ + struct spdk_scsi_dev dev = { 0 }; + struct spdk_scsi_task *task; + struct spdk_scsi_task *task_mgmt; + + task = spdk_get_task(NULL); + + spdk_scsi_dev_queue_task(&dev, task); + + task_mgmt = spdk_get_task(NULL); + + /* Enqueue the tasks into dev->task_mgmt_submit_queue */ + spdk_scsi_dev_queue_mgmt_task(&dev, task_mgmt, SPDK_SCSI_TASK_FUNC_LUN_RESET); + + spdk_scsi_task_put(task); + spdk_scsi_task_put(task_mgmt); +} + +static void +dev_add_port_max_ports(void) +{ + struct spdk_scsi_dev dev = { 0 }; + const char *name; + int id, rc; + + /* dev is set to SPDK_SCSI_DEV_MAX_PORTS */ + dev.num_ports = SPDK_SCSI_DEV_MAX_PORTS; + name = "Name of Port"; + id = 1; + + rc = spdk_scsi_dev_add_port(&dev, id, name); + + /* returns -1; since the dev already has maximum + * number of ports (SPDK_SCSI_DEV_MAX_PORTS) */ + CU_ASSERT_TRUE(rc < 0); +} + +static void +dev_add_port_construct_failure1(void) +{ + struct spdk_scsi_dev dev = { 0 }; + const int port_name_length = SPDK_SCSI_PORT_MAX_NAME_LENGTH + 2; + char name[port_name_length]; + uint64_t id; + int rc; + + dev.num_ports = 1; + /* Set the name such that the length exceeds SPDK_SCSI_PORT_MAX_NAME_LENGTH + * SPDK_SCSI_PORT_MAX_NAME_LENGTH = 256 */ + memset(name, 'a', port_name_length - 1); + name[port_name_length - 1] = '\0'; + id = 1; + + rc = spdk_scsi_dev_add_port(&dev, id, name); + + /* returns -1; since the length of the name exceeds + * SPDK_SCSI_PORT_MAX_NAME_LENGTH */ + CU_ASSERT_TRUE(rc < 0); +} + +static void +dev_add_port_construct_failure2(void) +{ + struct spdk_scsi_dev dev = { 0 }; + const char *name; + uint64_t id; + int rc; + + dev.num_ports = 1; + name = "Name of Port"; + id = 1; + + /* Initialize port[0] to be valid and its index is set to 1 */ + dev.port[0].id = id; + dev.port[0].is_used = 1; + + rc = spdk_scsi_dev_add_port(&dev, id, name); + + /* returns -1; since the dev already has a port whose index to be 1 */ + CU_ASSERT_TRUE(rc < 0); +} + +static void +dev_add_port_success1(void) +{ + struct spdk_scsi_dev dev = { 0 }; + const char *name; + int id, rc; + + dev.num_ports = 1; + name = "Name of Port"; + id = 1; + + rc = spdk_scsi_dev_add_port(&dev, id, name); + + /* successfully adds a port */ + CU_ASSERT_EQUAL(rc, 0); + /* Assert num_ports has been incremented to 2 */ + CU_ASSERT_EQUAL(dev.num_ports, 2); +} + +static void +dev_add_port_success2(void) +{ + struct spdk_scsi_dev dev = { 0 }; + const char *name; + uint64_t id; + int rc; + + dev.num_ports = 1; + name = "Name of Port"; + id = 1; + /* set id of invalid port[0] to 1. This must be ignored */ + dev.port[0].id = id; + dev.port[0].is_used = 0; + + rc = spdk_scsi_dev_add_port(&dev, id, name); + + /* successfully adds a port */ + CU_ASSERT_EQUAL(rc, 0); + /* Assert num_ports has been incremented to 1 */ + CU_ASSERT_EQUAL(dev.num_ports, 2); +} + +static void +dev_add_port_success3(void) +{ + struct spdk_scsi_dev dev = { 0 }; + const char *name; + uint64_t add_id; + int rc; + + dev.num_ports = 1; + name = "Name of Port"; + dev.port[0].id = 1; + dev.port[0].is_used = 1; + add_id = 2; + + /* Add a port with id = 2 */ + rc = spdk_scsi_dev_add_port(&dev, add_id, name); + + /* successfully adds a port */ + CU_ASSERT_EQUAL(rc, 0); + /* Assert num_ports has been incremented to 2 */ + CU_ASSERT_EQUAL(dev.num_ports, 2); +} + +static void +dev_find_port_by_id_num_ports_zero(void) +{ + struct spdk_scsi_dev dev = { 0 }; + struct spdk_scsi_port *rp_port; + uint64_t id; + + dev.num_ports = 0; + id = 1; + + rp_port = spdk_scsi_dev_find_port_by_id(&dev, id); + + /* returns null; since dev's num_ports is 0 */ + CU_ASSERT_TRUE(rp_port == NULL); +} + +static void +dev_find_port_by_id_id_not_found_failure(void) +{ + struct spdk_scsi_dev dev = { 0 }; + struct spdk_scsi_port *rp_port; + const char *name; + int rc; + uint64_t id, find_id; + + id = 1; + dev.num_ports = 1; + name = "Name of Port"; + find_id = 2; + + /* Add a port with id = 1 */ + rc = spdk_scsi_dev_add_port(&dev, id, name); + + CU_ASSERT_EQUAL(rc, 0); + + /* Find port with id = 2 */ + rp_port = spdk_scsi_dev_find_port_by_id(&dev, find_id); + + /* returns null; failed to find port specified by id = 2 */ + CU_ASSERT_TRUE(rp_port == NULL); +} + +static void +dev_find_port_by_id_success(void) +{ + struct spdk_scsi_dev dev = { 0 }; + struct spdk_scsi_port *rp_port; + const char *name; + int rc; + uint64_t id; + + id = 1; + dev.num_ports = 1; + name = "Name of Port"; + + /* Add a port */ + rc = spdk_scsi_dev_add_port(&dev, id, name); + + CU_ASSERT_EQUAL(rc, 0); + + /* Find port by the same id as the one added above */ + rp_port = spdk_scsi_dev_find_port_by_id(&dev, id); + + /* Successfully found port specified by id */ + CU_ASSERT_TRUE(rp_port != NULL); + if (rp_port != NULL) { + /* Assert the found port's id and name are same as + * the port added. */ + CU_ASSERT_EQUAL(rp_port->id, 1); + CU_ASSERT_STRING_EQUAL(rp_port->name, "Name of Port"); + } +} + +static void +dev_add_lun_bdev_not_found(void) +{ + int rc; + struct spdk_scsi_dev dev = {0}; + + rc = spdk_scsi_dev_add_lun(&dev, "malloc2", 0, NULL, NULL); + + SPDK_CU_ASSERT_FATAL(dev.lun[0] == NULL); + CU_ASSERT_NOT_EQUAL(rc, 0); +} + +static void +dev_add_lun_no_free_lun_id(void) +{ + int rc; + int i; + struct spdk_scsi_dev dev = {0}; + struct spdk_scsi_lun lun; + + for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { + dev.lun[i] = &lun; + } + + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); + + CU_ASSERT_NOT_EQUAL(rc, 0); +} + +static void +dev_add_lun_success1(void) +{ + int rc; + struct spdk_scsi_dev dev = {0}; + + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); + + CU_ASSERT_EQUAL(rc, 0); + + spdk_scsi_dev_destruct(&dev); +} + +static void +dev_add_lun_success2(void) +{ + int rc; + struct spdk_scsi_dev dev = {0}; + + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", 0, NULL, NULL); + + CU_ASSERT_EQUAL(rc, 0); + + spdk_scsi_dev_destruct(&dev); +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("dev_suite", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "destruct - null dev", + dev_destruct_null_dev) == NULL + || CU_add_test(suite, "destruct - zero luns", dev_destruct_zero_luns) == NULL + || CU_add_test(suite, "destruct - null lun", dev_destruct_null_lun) == NULL + || CU_add_test(suite, "destruct - success", dev_destruct_success) == NULL + || CU_add_test(suite, "construct - queue depth gt max depth", + dev_construct_num_luns_zero) == NULL + || CU_add_test(suite, "construct - no lun0", + dev_construct_no_lun_zero) == NULL + || CU_add_test(suite, "construct - null lun", + dev_construct_null_lun) == NULL + || CU_add_test(suite, "construct - name too long", dev_construct_name_too_long) == NULL + || CU_add_test(suite, "construct - success", dev_construct_success) == NULL + || CU_add_test(suite, "construct - success - LUN zero not first", + dev_construct_success_lun_zero_not_first) == NULL + || CU_add_test(suite, "dev queue task mgmt - success", + dev_queue_mgmt_task_success) == NULL + || CU_add_test(suite, "dev queue task - success", + dev_queue_task_success) == NULL + || CU_add_test(suite, "dev stop - success", dev_stop_success) == NULL + || CU_add_test(suite, "dev add port - max ports", + dev_add_port_max_ports) == NULL + || CU_add_test(suite, "dev add port - construct port failure 1", + dev_add_port_construct_failure1) == NULL + || CU_add_test(suite, "dev add port - construct port failure 2", + dev_add_port_construct_failure2) == NULL + || CU_add_test(suite, "dev add port - success 1", + dev_add_port_success1) == NULL + || CU_add_test(suite, "dev add port - success 2", + dev_add_port_success2) == NULL + || CU_add_test(suite, "dev add port - success 3", + dev_add_port_success3) == NULL + || CU_add_test(suite, "dev find port by id - num ports zero", + dev_find_port_by_id_num_ports_zero) == NULL + || CU_add_test(suite, "dev find port by id - different port id failure", + dev_find_port_by_id_id_not_found_failure) == NULL + || CU_add_test(suite, "dev find port by id - success", + dev_find_port_by_id_success) == NULL + || CU_add_test(suite, "dev add lun - bdev not found", + dev_add_lun_bdev_not_found) == NULL + || CU_add_test(suite, "dev add lun - no free lun id", + dev_add_lun_no_free_lun_id) == NULL + || CU_add_test(suite, "dev add lun - success 1", + dev_add_lun_success1) == NULL + || CU_add_test(suite, "dev add lun - success 2", + dev_add_lun_success2) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/src/spdk/test/unit/lib/scsi/lun.c/.gitignore b/src/spdk/test/unit/lib/scsi/lun.c/.gitignore new file mode 100644 index 00000000..89bd2aaf --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/lun.c/.gitignore @@ -0,0 +1 @@ +lun_ut diff --git a/src/spdk/test/unit/lib/scsi/lun.c/Makefile b/src/spdk/test/unit/lib/scsi/lun.c/Makefile new file mode 100644 index 00000000..22841b0d --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/lun.c/Makefile @@ -0,0 +1,40 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +TEST_FILE = lun_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/scsi/lun.c/lun_ut.c b/src/spdk/test/unit/lib/scsi/lun.c/lun_ut.c new file mode 100644 index 00000000..2237e8ed --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/lun.c/lun_ut.c @@ -0,0 +1,654 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" + +#include "scsi/task.c" +#include "scsi/lun.c" + +#include "spdk_internal/mock.h" + +/* Unit test bdev mockup */ +struct spdk_bdev { + int x; +}; + +SPDK_LOG_REGISTER_COMPONENT("scsi", SPDK_LOG_SCSI) + +struct spdk_scsi_globals g_spdk_scsi; + +static bool g_lun_execute_fail = false; +static int g_lun_execute_status = SPDK_SCSI_TASK_PENDING; +static uint32_t g_task_count = 0; + +struct spdk_poller * +spdk_poller_register(spdk_poller_fn fn, + void *arg, + uint64_t period_microseconds) +{ + return NULL; +} + +void +spdk_poller_unregister(struct spdk_poller **ppoller) +{ +} + +void +spdk_thread_send_msg(const struct spdk_thread *thread, spdk_thread_fn fn, void *ctx) +{ +} + +struct spdk_trace_histories *g_trace_histories; +void _spdk_trace_record(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id, + uint32_t size, uint64_t object_id, uint64_t arg1) +{ +} + +static void +spdk_lun_ut_cpl_task(struct spdk_scsi_task *task) +{ + SPDK_CU_ASSERT_FATAL(g_task_count > 0); + g_task_count--; +} + +static void +spdk_lun_ut_free_task(struct spdk_scsi_task *task) +{ +} + +static void +ut_init_task(struct spdk_scsi_task *task) +{ + memset(task, 0, sizeof(*task)); + spdk_scsi_task_construct(task, spdk_lun_ut_cpl_task, + spdk_lun_ut_free_task); + g_task_count++; +} + +void * +spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr) +{ + void *buf = malloc(size); + if (phys_addr) { + *phys_addr = (uint64_t)buf; + } + return buf; +} + +void * +spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr) +{ + void *buf = calloc(size, 1); + if (phys_addr) { + *phys_addr = (uint64_t)buf; + } + return buf; +} + +void +spdk_dma_free(void *buf) +{ + free(buf); +} + +void +spdk_bdev_free_io(struct spdk_bdev_io *bdev_io) +{ + CU_ASSERT(0); +} + +int +spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb, + void *remove_ctx, struct spdk_bdev_desc **desc) +{ + return 0; +} + +void +spdk_bdev_close(struct spdk_bdev_desc *desc) +{ +} + +const char * +spdk_bdev_get_name(const struct spdk_bdev *bdev) +{ + return "test"; +} + +void spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev, + struct spdk_scsi_task *task, + enum spdk_scsi_task_func func) +{ +} + +void spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, + struct spdk_scsi_lun *lun) +{ + return; +} + +void +spdk_bdev_scsi_reset(struct spdk_scsi_task *task) +{ + return; +} + +int +spdk_bdev_scsi_execute(struct spdk_scsi_task *task) +{ + if (g_lun_execute_fail) { + return -EINVAL; + } else { + task->status = SPDK_SCSI_STATUS_GOOD; + + if (g_lun_execute_status == SPDK_SCSI_TASK_PENDING) { + return g_lun_execute_status; + } else if (g_lun_execute_status == SPDK_SCSI_TASK_COMPLETE) { + return g_lun_execute_status; + } else { + return 0; + } + } +} + +struct spdk_io_channel * +spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc) +{ + return NULL; +} + +void +spdk_put_io_channel(struct spdk_io_channel *ch) +{ +} + +DEFINE_STUB(spdk_io_channel_get_thread, struct spdk_thread *, (struct spdk_io_channel *ch), NULL) +DEFINE_STUB(spdk_get_thread, struct spdk_thread *, (void), NULL) + +static _spdk_scsi_lun * +lun_construct(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_bdev bdev; + + lun = spdk_scsi_lun_construct(&bdev, NULL, NULL); + + SPDK_CU_ASSERT_FATAL(lun != NULL); + return lun; +} + +static void +lun_destruct(struct spdk_scsi_lun *lun) +{ + /* LUN will defer its removal if there are any unfinished tasks */ + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&lun->tasks)); + + spdk_scsi_lun_destruct(lun); +} + +static void +lun_task_mgmt_execute_null_task(void) +{ + int rc; + + rc = spdk_scsi_lun_task_mgmt_execute(NULL, SPDK_SCSI_TASK_FUNC_ABORT_TASK); + + /* returns -1 since we passed NULL for the task */ + CU_ASSERT_TRUE(rc < 0); + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_task_mgmt_execute_abort_task_null_lun_failure(void) +{ + struct spdk_scsi_task mgmt_task = { 0 }; + struct spdk_scsi_port initiator_port = { 0 }; + int rc; + + ut_init_task(&mgmt_task); + mgmt_task.lun = NULL; + mgmt_task.initiator_port = &initiator_port; + + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, SPDK_SCSI_TASK_FUNC_ABORT_TASK); + + /* returns -1 since we passed NULL for LUN */ + CU_ASSERT_TRUE(rc < 0); + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_task_mgmt_execute_abort_task_not_supported(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_scsi_task task = { 0 }; + struct spdk_scsi_task mgmt_task = { 0 }; + struct spdk_scsi_port initiator_port = { 0 }; + struct spdk_scsi_dev dev = { 0 }; + uint8_t cdb[6] = { 0 }; + int rc; + + lun = lun_construct(); + lun->dev = &dev; + + ut_init_task(&mgmt_task); + mgmt_task.lun = lun; + mgmt_task.initiator_port = &initiator_port; + + /* Params to add regular task to the lun->tasks */ + ut_init_task(&task); + task.lun = lun; + task.cdb = cdb; + + spdk_scsi_lun_execute_task(lun, &task); + + /* task should now be on the tasks list */ + CU_ASSERT(!TAILQ_EMPTY(&lun->tasks)); + + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, SPDK_SCSI_TASK_FUNC_ABORT_TASK); + + /* returns -1 since task abort is not supported */ + CU_ASSERT_TRUE(rc < 0); + CU_ASSERT(mgmt_task.response == SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED); + + /* task is still on the tasks list */ + CU_ASSERT_EQUAL(g_task_count, 1); + + spdk_scsi_lun_complete_task(lun, &task); + CU_ASSERT_EQUAL(g_task_count, 0); + + lun_destruct(lun); +} + +static void +lun_task_mgmt_execute_abort_task_all_null_lun_failure(void) +{ + struct spdk_scsi_task mgmt_task = { 0 }; + struct spdk_scsi_port initiator_port = { 0 }; + int rc; + + ut_init_task(&mgmt_task); + mgmt_task.lun = NULL; + mgmt_task.initiator_port = &initiator_port; + + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET); + + /* Returns -1 since we passed NULL for lun */ + CU_ASSERT_TRUE(rc < 0); + + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_task_mgmt_execute_abort_task_all_not_supported(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_scsi_task task = { 0 }; + struct spdk_scsi_task mgmt_task = { 0 }; + struct spdk_scsi_port initiator_port = { 0 }; + struct spdk_scsi_dev dev = { 0 }; + int rc; + uint8_t cdb[6] = { 0 }; + + lun = lun_construct(); + lun->dev = &dev; + + ut_init_task(&mgmt_task); + mgmt_task.lun = lun; + mgmt_task.initiator_port = &initiator_port; + + /* Params to add regular task to the lun->tasks */ + ut_init_task(&task); + task.initiator_port = &initiator_port; + task.lun = lun; + task.cdb = cdb; + + spdk_scsi_lun_execute_task(lun, &task); + + /* task should now be on the tasks list */ + CU_ASSERT(!TAILQ_EMPTY(&lun->tasks)); + + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET); + + /* returns -1 since task abort is not supported */ + CU_ASSERT_TRUE(rc < 0); + CU_ASSERT(mgmt_task.response == SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED); + + /* task is still on the tasks list */ + CU_ASSERT_EQUAL(g_task_count, 1); + + spdk_scsi_lun_complete_task(lun, &task); + + CU_ASSERT_EQUAL(g_task_count, 0); + + lun_destruct(lun); +} + +static void +lun_task_mgmt_execute_lun_reset_failure(void) +{ + struct spdk_scsi_task mgmt_task = { 0 }; + int rc; + + ut_init_task(&mgmt_task); + mgmt_task.lun = NULL; + + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, SPDK_SCSI_TASK_FUNC_LUN_RESET); + + /* Returns -1 since we passed NULL for lun */ + CU_ASSERT_TRUE(rc < 0); + + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_task_mgmt_execute_lun_reset(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_scsi_task mgmt_task = { 0 }; + struct spdk_scsi_dev dev = { 0 }; + int rc; + + lun = lun_construct(); + lun->dev = &dev; + + ut_init_task(&mgmt_task); + mgmt_task.lun = lun; + + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, SPDK_SCSI_TASK_FUNC_LUN_RESET); + + /* Returns success */ + CU_ASSERT_EQUAL(rc, 0); + + lun_destruct(lun); + + /* task is still on the tasks list */ + CU_ASSERT_EQUAL(g_task_count, 1); + g_task_count = 0; +} + +static void +lun_task_mgmt_execute_invalid_case(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_scsi_task mgmt_task = { 0 }; + struct spdk_scsi_dev dev = { 0 }; + int rc; + + lun = lun_construct(); + lun->dev = &dev; + + ut_init_task(&mgmt_task); + /* Pass an invalid value to the switch statement */ + rc = spdk_scsi_lun_task_mgmt_execute(&mgmt_task, 5); + + /* Returns -1 on passing an invalid value to the switch case */ + CU_ASSERT_TRUE(rc < 0); + + lun_destruct(lun); + + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_append_task_null_lun_task_cdb_spc_inquiry(void) +{ + struct spdk_scsi_task task = { 0 }; + uint8_t cdb[6] = { 0 }; + + ut_init_task(&task); + task.cdb = cdb; + task.cdb[0] = SPDK_SPC_INQUIRY; + /* alloc_len >= 4096 */ + task.cdb[3] = 0xFF; + task.cdb[4] = 0xFF; + task.lun = NULL; + + spdk_scsi_task_process_null_lun(&task); + + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_GOOD); + + spdk_scsi_task_put(&task); + + /* spdk_scsi_task_process_null_lun() does not call cpl_fn */ + CU_ASSERT_EQUAL(g_task_count, 1); + g_task_count = 0; +} + +static void +lun_append_task_null_lun_alloc_len_lt_4096(void) +{ + struct spdk_scsi_task task = { 0 }; + uint8_t cdb[6] = { 0 }; + + ut_init_task(&task); + task.cdb = cdb; + task.cdb[0] = SPDK_SPC_INQUIRY; + /* alloc_len < 4096 */ + task.cdb[3] = 0; + task.cdb[4] = 0; + /* alloc_len is set to a minimal value of 4096 + * Hence, buf of size 4096 is allocated */ + spdk_scsi_task_process_null_lun(&task); + + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_GOOD); + + spdk_scsi_task_put(&task); + + /* spdk_scsi_task_process_null_lun() does not call cpl_fn */ + CU_ASSERT_EQUAL(g_task_count, 1); + g_task_count = 0; +} + +static void +lun_append_task_null_lun_not_supported(void) +{ + struct spdk_scsi_task task = { 0 }; + uint8_t cdb[6] = { 0 }; + + ut_init_task(&task); + task.cdb = cdb; + task.lun = NULL; + + spdk_scsi_task_process_null_lun(&task); + + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION); + /* LUN not supported; task's data transferred should be 0 */ + CU_ASSERT_EQUAL(task.data_transferred, 0); + + /* spdk_scsi_task_process_null_lun() does not call cpl_fn */ + CU_ASSERT_EQUAL(g_task_count, 1); + g_task_count = 0; +} + +static void +lun_execute_scsi_task_pending(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_scsi_task task = { 0 }; + struct spdk_scsi_dev dev = { 0 }; + + lun = lun_construct(); + + ut_init_task(&task); + task.lun = lun; + lun->dev = &dev; + + g_lun_execute_fail = false; + g_lun_execute_status = SPDK_SCSI_TASK_PENDING; + + /* the tasks list should still be empty since it has not been + executed yet + */ + CU_ASSERT(TAILQ_EMPTY(&lun->tasks)); + + spdk_scsi_lun_execute_task(lun, &task); + + /* Assert the task has been successfully added to the tasks queue */ + CU_ASSERT(!TAILQ_EMPTY(&lun->tasks)); + + /* task is still on the tasks list */ + CU_ASSERT_EQUAL(g_task_count, 1); + + /* Need to complete task so LUN might be removed right now */ + spdk_scsi_lun_complete_task(lun, &task); + + CU_ASSERT_EQUAL(g_task_count, 0); + + lun_destruct(lun); +} + +static void +lun_execute_scsi_task_complete(void) +{ + struct spdk_scsi_lun *lun; + struct spdk_scsi_task task = { 0 }; + struct spdk_scsi_dev dev = { 0 }; + + lun = lun_construct(); + + ut_init_task(&task); + task.lun = lun; + lun->dev = &dev; + + g_lun_execute_fail = false; + g_lun_execute_status = SPDK_SCSI_TASK_COMPLETE; + + /* the tasks list should still be empty since it has not been + executed yet + */ + CU_ASSERT(TAILQ_EMPTY(&lun->tasks)); + + spdk_scsi_lun_execute_task(lun, &task); + + /* Assert the task has not been added to the tasks queue */ + CU_ASSERT(TAILQ_EMPTY(&lun->tasks)); + + lun_destruct(lun); + + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_destruct_success(void) +{ + struct spdk_scsi_lun *lun; + + lun = lun_construct(); + + spdk_scsi_lun_destruct(lun); + + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_construct_null_ctx(void) +{ + struct spdk_scsi_lun *lun; + + lun = spdk_scsi_lun_construct(NULL, NULL, NULL); + + /* lun should be NULL since we passed NULL for the ctx pointer. */ + CU_ASSERT(lun == NULL); + CU_ASSERT_EQUAL(g_task_count, 0); +} + +static void +lun_construct_success(void) +{ + struct spdk_scsi_lun *lun = lun_construct(); + + lun_destruct(lun); + + CU_ASSERT_EQUAL(g_task_count, 0); +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("lun_suite", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "task management - null task failure", + lun_task_mgmt_execute_null_task) == NULL + || CU_add_test(suite, "task management abort task - null lun failure", + lun_task_mgmt_execute_abort_task_null_lun_failure) == NULL + || CU_add_test(suite, "task management abort task - not supported", + lun_task_mgmt_execute_abort_task_not_supported) == NULL + || CU_add_test(suite, "task management abort task set - null lun failure", + lun_task_mgmt_execute_abort_task_all_null_lun_failure) == NULL + || CU_add_test(suite, "task management abort task set - success", + lun_task_mgmt_execute_abort_task_all_not_supported) == NULL + || CU_add_test(suite, "task management - lun reset failure", + lun_task_mgmt_execute_lun_reset_failure) == NULL + || CU_add_test(suite, "task management - lun reset success", + lun_task_mgmt_execute_lun_reset) == NULL + || CU_add_test(suite, "task management - invalid option", + lun_task_mgmt_execute_invalid_case) == NULL + || CU_add_test(suite, "append task - null lun SPDK_SPC_INQUIRY", + lun_append_task_null_lun_task_cdb_spc_inquiry) == NULL + || CU_add_test(suite, "append task - allocated length less than 4096", + lun_append_task_null_lun_alloc_len_lt_4096) == NULL + || CU_add_test(suite, "append task - unsupported lun", + lun_append_task_null_lun_not_supported) == NULL + || CU_add_test(suite, "execute task - scsi task pending", + lun_execute_scsi_task_pending) == NULL + || CU_add_test(suite, "execute task - scsi task complete", + lun_execute_scsi_task_complete) == NULL + || CU_add_test(suite, "destruct task - success", lun_destruct_success) == NULL + || CU_add_test(suite, "construct - null ctx", lun_construct_null_ctx) == NULL + || CU_add_test(suite, "construct - success", lun_construct_success) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + return num_failures; +} diff --git a/src/spdk/test/unit/lib/scsi/scsi.c/.gitignore b/src/spdk/test/unit/lib/scsi/scsi.c/.gitignore new file mode 100644 index 00000000..99a7db2b --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/scsi.c/.gitignore @@ -0,0 +1 @@ +scsi_ut diff --git a/src/spdk/test/unit/lib/scsi/scsi.c/Makefile b/src/spdk/test/unit/lib/scsi/scsi.c/Makefile new file mode 100644 index 00000000..86893653 --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/scsi.c/Makefile @@ -0,0 +1,41 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +SPDK_LIB_LIST = trace +TEST_FILE = scsi_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/scsi/scsi.c/scsi_ut.c b/src/spdk/test/unit/lib/scsi/scsi.c/scsi_ut.c new file mode 100644 index 00000000..5a1a31f6 --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/scsi.c/scsi_ut.c @@ -0,0 +1,80 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk/scsi.h" + +#include "spdk_cunit.h" + +#include "scsi/scsi.c" + +static void +scsi_init(void) +{ + int rc; + + rc = spdk_scsi_init(); + CU_ASSERT_EQUAL(rc, 0); +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("scsi_suite", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "scsi init", \ + scsi_init) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + return num_failures; +} diff --git a/src/spdk/test/unit/lib/scsi/scsi_bdev.c/.gitignore b/src/spdk/test/unit/lib/scsi/scsi_bdev.c/.gitignore new file mode 100644 index 00000000..8f1ecc12 --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/scsi_bdev.c/.gitignore @@ -0,0 +1 @@ +scsi_bdev_ut diff --git a/src/spdk/test/unit/lib/scsi/scsi_bdev.c/Makefile b/src/spdk/test/unit/lib/scsi/scsi_bdev.c/Makefile new file mode 100644 index 00000000..abb1de50 --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/scsi_bdev.c/Makefile @@ -0,0 +1,40 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +TEST_FILE = scsi_bdev_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c b/src/spdk/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c new file mode 100644 index 00000000..4deb2cec --- /dev/null +++ b/src/spdk/test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut.c @@ -0,0 +1,988 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "scsi/task.c" +#include "scsi/scsi_bdev.c" + +#include "spdk_cunit.h" + +SPDK_LOG_REGISTER_COMPONENT("scsi", SPDK_LOG_SCSI) + +struct spdk_scsi_globals g_spdk_scsi; + +static uint64_t g_test_bdev_num_blocks; + +TAILQ_HEAD(, spdk_bdev_io) g_bdev_io_queue; +int g_scsi_cb_called = 0; + +TAILQ_HEAD(, spdk_bdev_io_wait_entry) g_io_wait_queue; +bool g_bdev_io_pool_full = false; + +void * +spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr) +{ + void *buf = malloc(size); + if (phys_addr) { + *phys_addr = (uint64_t)buf; + } + + return buf; +} + +void * +spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr) +{ + void *buf = calloc(size, 1); + if (phys_addr) { + *phys_addr = (uint64_t)buf; + } + + return buf; +} + +void +spdk_dma_free(void *buf) +{ + free(buf); +} + +bool +spdk_bdev_io_type_supported(struct spdk_bdev *bdev, enum spdk_bdev_io_type io_type) +{ + abort(); + return false; +} + +void +spdk_bdev_free_io(struct spdk_bdev_io *bdev_io) +{ + CU_ASSERT(0); +} + +const char * +spdk_bdev_get_name(const struct spdk_bdev *bdev) +{ + return "test"; +} + +uint32_t +spdk_bdev_get_block_size(const struct spdk_bdev *bdev) +{ + return 512; +} + +uint64_t +spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev) +{ + return g_test_bdev_num_blocks; +} + +const char * +spdk_bdev_get_product_name(const struct spdk_bdev *bdev) +{ + return "test product"; +} + +bool +spdk_bdev_has_write_cache(const struct spdk_bdev *bdev) +{ + return false; +} + +void +spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) +{ + g_scsi_cb_called++; +} + +void +spdk_scsi_lun_complete_mgmt_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) +{ +} + +static void +ut_put_task(struct spdk_scsi_task *task) +{ + if (task->alloc_len) { + free(task->iov.iov_base); + } + + task->iov.iov_base = NULL; + task->iov.iov_len = 0; + task->alloc_len = 0; + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_io_queue)); +} + + +static void +ut_init_task(struct spdk_scsi_task *task) +{ + memset(task, 0xFF, sizeof(*task)); + task->iov.iov_base = NULL; + task->iovs = &task->iov; + task->iovcnt = 1; + task->alloc_len = 0; + task->dxfer_dir = SPDK_SCSI_DIR_NONE; +} + +void +spdk_bdev_io_get_scsi_status(const struct spdk_bdev_io *bdev_io, + int *sc, int *sk, int *asc, int *ascq) +{ + switch (bdev_io->internal.status) { + case SPDK_BDEV_IO_STATUS_SUCCESS: + *sc = SPDK_SCSI_STATUS_GOOD; + *sk = SPDK_SCSI_SENSE_NO_SENSE; + *asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; + *ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case SPDK_BDEV_IO_STATUS_SCSI_ERROR: + *sc = bdev_io->internal.error.scsi.sc; + *sk = bdev_io->internal.error.scsi.sk; + *asc = bdev_io->internal.error.scsi.asc; + *ascq = bdev_io->internal.error.scsi.ascq; + break; + default: + *sc = SPDK_SCSI_STATUS_CHECK_CONDITION; + *sk = SPDK_SCSI_SENSE_ABORTED_COMMAND; + *asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE; + *ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + } +} + +void +spdk_bdev_io_get_iovec(struct spdk_bdev_io *bdev_io, struct iovec **iovp, int *iovcntp) +{ + *iovp = NULL; + *iovcntp = 0; +} + +static void +ut_bdev_io_flush(void) +{ + struct spdk_bdev_io *bdev_io; + struct spdk_bdev_io_wait_entry *entry; + + while (!TAILQ_EMPTY(&g_bdev_io_queue) || !TAILQ_EMPTY(&g_io_wait_queue)) { + while (!TAILQ_EMPTY(&g_bdev_io_queue)) { + bdev_io = TAILQ_FIRST(&g_bdev_io_queue); + TAILQ_REMOVE(&g_bdev_io_queue, bdev_io, internal.link); + bdev_io->internal.cb(bdev_io, true, bdev_io->internal.caller_ctx); + free(bdev_io); + } + + while (!TAILQ_EMPTY(&g_io_wait_queue)) { + entry = TAILQ_FIRST(&g_io_wait_queue); + TAILQ_REMOVE(&g_io_wait_queue, entry, link); + entry->cb_fn(entry->cb_arg); + } + } +} + +static int +_spdk_bdev_io_op(spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + struct spdk_bdev_io *bdev_io; + + if (g_bdev_io_pool_full) { + g_bdev_io_pool_full = false; + return -ENOMEM; + } + + bdev_io = calloc(1, sizeof(*bdev_io)); + SPDK_CU_ASSERT_FATAL(bdev_io != NULL); + bdev_io->internal.status = SPDK_BDEV_IO_STATUS_SUCCESS; + bdev_io->internal.cb = cb; + bdev_io->internal.caller_ctx = cb_arg; + + TAILQ_INSERT_TAIL(&g_bdev_io_queue, bdev_io, internal.link); + + return 0; +} + +int +spdk_bdev_readv(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + struct iovec *iov, int iovcnt, uint64_t offset, uint64_t nbytes, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + return _spdk_bdev_io_op(cb, cb_arg); +} + +int +spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + struct iovec *iov, int iovcnt, + uint64_t offset, uint64_t len, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + return _spdk_bdev_io_op(cb, cb_arg); +} + +int +spdk_bdev_unmap_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + return _spdk_bdev_io_op(cb, cb_arg); +} + +int +spdk_bdev_reset(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + return _spdk_bdev_io_op(cb, cb_arg); +} + +int +spdk_bdev_flush_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + return _spdk_bdev_io_op(cb, cb_arg); +} + +int +spdk_bdev_queue_io_wait(struct spdk_bdev *bdev, struct spdk_io_channel *ch, + struct spdk_bdev_io_wait_entry *entry) +{ + TAILQ_INSERT_TAIL(&g_io_wait_queue, entry, link); + return 0; +} + +/* + * This test specifically tests a mode select 6 command from the + * Windows SCSI compliance test that caused SPDK to crash. + */ +static void +mode_select_6_test(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + char cdb[16]; + char data[24]; + int rc; + + ut_init_task(&task); + + cdb[0] = 0x15; + cdb[1] = 0x11; + cdb[2] = 0x00; + cdb[3] = 0x00; + cdb[4] = 0x18; + cdb[5] = 0x00; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + memset(data, 0, sizeof(data)); + data[4] = 0x08; + data[5] = 0x02; + spdk_scsi_task_set_data(&task, data, sizeof(data)); + + rc = spdk_bdev_scsi_execute(&task); + + CU_ASSERT_EQUAL(rc, 0); + + ut_put_task(&task); +} + +/* + * This test specifically tests a mode select 6 command which + * contains no mode pages. + */ +static void +mode_select_6_test2(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + char cdb[16]; + int rc; + + ut_init_task(&task); + + cdb[0] = 0x15; + cdb[1] = 0x00; + cdb[2] = 0x00; + cdb[3] = 0x00; + cdb[4] = 0x00; + cdb[5] = 0x00; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + rc = spdk_bdev_scsi_execute(&task); + + CU_ASSERT_EQUAL(rc, 0); + + ut_put_task(&task); +} + +/* + * This test specifically tests a mode sense 6 command which + * return all subpage 00h mode pages. + */ +static void +mode_sense_6_test(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + char cdb[12]; + unsigned char *data; + int rc; + unsigned char mode_data_len = 0; + unsigned char medium_type = 0; + unsigned char dev_specific_param = 0; + unsigned char blk_descriptor_len = 0; + + memset(&bdev, 0, sizeof(struct spdk_bdev)); + ut_init_task(&task); + memset(cdb, 0, sizeof(cdb)); + + cdb[0] = 0x1A; + cdb[2] = 0x3F; + cdb[4] = 0xFF; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + rc = spdk_bdev_scsi_execute(&task); + SPDK_CU_ASSERT_FATAL(rc == 0); + + data = task.iovs[0].iov_base; + mode_data_len = data[0]; + medium_type = data[1]; + dev_specific_param = data[2]; + blk_descriptor_len = data[3]; + + CU_ASSERT(mode_data_len >= 11); + CU_ASSERT_EQUAL(medium_type, 0); + CU_ASSERT_EQUAL(dev_specific_param, 0); + CU_ASSERT_EQUAL(blk_descriptor_len, 8); + + ut_put_task(&task); +} + +/* + * This test specifically tests a mode sense 10 command which + * return all subpage 00h mode pages. + */ +static void +mode_sense_10_test(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + char cdb[12]; + unsigned char *data; + int rc; + unsigned short mode_data_len = 0; + unsigned char medium_type = 0; + unsigned char dev_specific_param = 0; + unsigned short blk_descriptor_len = 0; + + memset(&bdev, 0, sizeof(struct spdk_bdev)); + ut_init_task(&task); + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x5A; + cdb[2] = 0x3F; + cdb[8] = 0xFF; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + rc = spdk_bdev_scsi_execute(&task); + SPDK_CU_ASSERT_FATAL(rc == 0); + + data = task.iovs[0].iov_base; + mode_data_len = ((data[0] << 8) + data[1]); + medium_type = data[2]; + dev_specific_param = data[3]; + blk_descriptor_len = ((data[6] << 8) + data[7]); + + CU_ASSERT(mode_data_len >= 14); + CU_ASSERT_EQUAL(medium_type, 0); + CU_ASSERT_EQUAL(dev_specific_param, 0); + CU_ASSERT_EQUAL(blk_descriptor_len, 8); + + ut_put_task(&task); +} + +/* + * This test specifically tests a scsi inquiry command from the + * Windows SCSI compliance test that failed to return the + * expected SCSI error sense code. + */ +static void +inquiry_evpd_test(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + char cdb[6]; + int rc; + + ut_init_task(&task); + + cdb[0] = 0x12; + cdb[1] = 0x00; // EVPD = 0 + cdb[2] = 0xff; // PageCode non-zero + cdb[3] = 0x00; + cdb[4] = 0xff; + cdb[5] = 0x00; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + rc = spdk_bdev_scsi_execute(&task); + SPDK_CU_ASSERT_FATAL(rc == 0); + + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task.sense_data[2] & 0xf, SPDK_SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task.sense_data[12], 0x24); + CU_ASSERT_EQUAL(task.sense_data[13], 0x0); + + ut_put_task(&task); +} + +/* + * This test is to verify specific return data for a standard scsi inquiry + * command: Version + */ +static void +inquiry_standard_test(void) +{ + struct spdk_bdev bdev = { .blocklen = 512 }; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + char cdb[6]; + char *data; + struct spdk_scsi_cdb_inquiry_data *inq_data; + int rc; + + ut_init_task(&task); + + cdb[0] = 0x12; + cdb[1] = 0x00; // EVPD = 0 + cdb[2] = 0x00; // PageCode zero - requesting standard inquiry + cdb[3] = 0x00; + cdb[4] = 0xff; // Indicate data size used by conformance test + cdb[5] = 0x00; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + rc = spdk_bdev_scsi_execute(&task); + + data = task.iovs[0].iov_base; + inq_data = (struct spdk_scsi_cdb_inquiry_data *)&data[0]; + + CU_ASSERT_EQUAL(inq_data->version, SPDK_SPC_VERSION_SPC3); + CU_ASSERT_EQUAL(rc, 0); + + ut_put_task(&task); +} + +static void +_inquiry_overflow_test(uint8_t alloc_len) +{ + struct spdk_bdev bdev = { .blocklen = 512 }; + struct spdk_scsi_task task; + struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev; + uint8_t cdb[6]; + int rc; + /* expects a 4K internal data buffer */ + char data[4096], data_compare[4096]; + + ut_init_task(&task); + + cdb[0] = 0x12; + cdb[1] = 0x00; // EVPD = 0 + cdb[2] = 0x00; // PageCode zero - requesting standard inquiry + cdb[3] = 0x00; + cdb[4] = alloc_len; // Indicate data size used by conformance test + cdb[5] = 0x00; + task.cdb = cdb; + + snprintf(&dev.name[0], sizeof(dev.name), "spdk_iscsi_translation_test"); + lun.bdev = &bdev; + lun.dev = &dev; + task.lun = &lun; + + memset(data, 0, sizeof(data)); + memset(data_compare, 0, sizeof(data_compare)); + + spdk_scsi_task_set_data(&task, data, sizeof(data)); + + rc = spdk_bdev_scsi_execute(&task); + SPDK_CU_ASSERT_FATAL(rc == 0); + + CU_ASSERT_EQUAL(memcmp(data + alloc_len, data_compare + alloc_len, sizeof(data) - alloc_len), 0); + CU_ASSERT(task.data_transferred <= alloc_len); + + ut_put_task(&task); +} + +static void +inquiry_overflow_test(void) +{ + int i; + + for (i = 0; i < 256; i++) { + _inquiry_overflow_test(i); + } +} + +static void +scsi_name_padding_test(void) +{ + char name[SPDK_SCSI_DEV_MAX_NAME + 1]; + char buf[SPDK_SCSI_DEV_MAX_NAME + 1]; + int written, i; + + /* case 1 */ + memset(name, '\0', sizeof(name)); + memset(name, 'x', 251); + written = spdk_bdev_scsi_pad_scsi_name(buf, name); + + CU_ASSERT(written == 252); + CU_ASSERT(buf[250] == 'x'); + CU_ASSERT(buf[251] == '\0'); + + /* case 2: */ + memset(name, '\0', sizeof(name)); + memset(name, 'x', 252); + written = spdk_bdev_scsi_pad_scsi_name(buf, name); + + CU_ASSERT(written == 256); + CU_ASSERT(buf[251] == 'x'); + for (i = 252; i < 256; i++) { + CU_ASSERT(buf[i] == '\0'); + } + + /* case 3 */ + memset(name, '\0', sizeof(name)); + memset(name, 'x', 255); + written = spdk_bdev_scsi_pad_scsi_name(buf, name); + + CU_ASSERT(written == 256); + CU_ASSERT(buf[254] == 'x'); + CU_ASSERT(buf[255] == '\0'); +} + +/* + * This test is to verify specific error translation from bdev to scsi. + */ +static void +task_complete_test(void) +{ + struct spdk_scsi_task task; + struct spdk_bdev_io bdev_io = {}; + struct spdk_scsi_lun lun; + + ut_init_task(&task); + + TAILQ_INIT(&lun.tasks); + TAILQ_INSERT_TAIL(&lun.tasks, &task, scsi_link); + task.lun = &lun; + + bdev_io.internal.status = SPDK_BDEV_IO_STATUS_SUCCESS; + spdk_bdev_scsi_task_complete_cmd(&bdev_io, bdev_io.internal.status, &task); + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + bdev_io.internal.status = SPDK_BDEV_IO_STATUS_SCSI_ERROR; + bdev_io.internal.error.scsi.sc = SPDK_SCSI_STATUS_CHECK_CONDITION; + bdev_io.internal.error.scsi.sk = SPDK_SCSI_SENSE_HARDWARE_ERROR; + bdev_io.internal.error.scsi.asc = SPDK_SCSI_ASC_WARNING; + bdev_io.internal.error.scsi.ascq = SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED; + spdk_bdev_scsi_task_complete_cmd(&bdev_io, bdev_io.internal.status, &task); + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task.sense_data[2] & 0xf, SPDK_SCSI_SENSE_HARDWARE_ERROR); + CU_ASSERT_EQUAL(task.sense_data[12], SPDK_SCSI_ASC_WARNING); + CU_ASSERT_EQUAL(task.sense_data[13], SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + bdev_io.internal.status = SPDK_BDEV_IO_STATUS_FAILED; + spdk_bdev_scsi_task_complete_cmd(&bdev_io, bdev_io.internal.status, &task); + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task.sense_data[2] & 0xf, SPDK_SCSI_SENSE_ABORTED_COMMAND); + CU_ASSERT_EQUAL(task.sense_data[12], SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE); + CU_ASSERT_EQUAL(task.sense_data[13], SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + ut_put_task(&task); +} + +static void +lba_range_test(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_lun lun; + struct spdk_scsi_task task; + uint8_t cdb[16]; + int rc; + + lun.bdev = &bdev; + + ut_init_task(&task); + task.lun = &lun; + task.lun->bdev_desc = NULL; + task.lun->io_channel = NULL; + task.cdb = cdb; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x88; /* READ (16) */ + + /* Test block device size of 4 blocks */ + g_test_bdev_num_blocks = 4; + + /* LBA = 0, length = 1 (in range) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 1); /* transfer length */ + task.transfer_len = 1 * 512; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&g_bdev_io_queue)); + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + /* LBA = 4, length = 1 (LBA out of range) */ + to_be64(&cdb[2], 4); /* LBA */ + to_be32(&cdb[10], 1); /* transfer length */ + task.transfer_len = 1 * 512; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_COMPLETE); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT(task.sense_data[12] == SPDK_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE); + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_io_queue)); + + /* LBA = 0, length = 4 (in range, max valid size) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 4); /* transfer length */ + task.transfer_len = 4 * 512; + task.status = 0xFF; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&g_bdev_io_queue)); + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + /* LBA = 0, length = 5 (LBA in range, length beyond end of bdev) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 5); /* transfer length */ + task.transfer_len = 5 * 512; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_COMPLETE); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT(task.sense_data[12] == SPDK_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE); + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_io_queue)); + + ut_put_task(&task); +} + +static void +xfer_len_test(void) +{ + struct spdk_bdev bdev; + struct spdk_scsi_lun lun; + struct spdk_scsi_task task; + uint8_t cdb[16]; + int rc; + + lun.bdev = &bdev; + + ut_init_task(&task); + task.lun = &lun; + task.lun->bdev_desc = NULL; + task.lun->io_channel = NULL; + task.cdb = cdb; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x88; /* READ (16) */ + + /* Test block device size of 512 MiB */ + g_test_bdev_num_blocks = 512 * 1024 * 1024; + + /* 1 block */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 1); /* transfer length */ + task.transfer_len = 1 * 512; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&g_bdev_io_queue)); + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + /* max transfer length (as reported in block limits VPD page) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], SPDK_WORK_BLOCK_SIZE / 512); /* transfer length */ + task.transfer_len = SPDK_WORK_BLOCK_SIZE; + task.status = 0xFF; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&g_bdev_io_queue)); + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + + /* max transfer length plus one block (invalid) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], SPDK_WORK_BLOCK_SIZE / 512 + 1); /* transfer length */ + task.transfer_len = SPDK_WORK_BLOCK_SIZE + 512; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_COMPLETE); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT((task.sense_data[2] & 0xf) == SPDK_SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT(task.sense_data[12] == SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB); + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_io_queue)); + + /* zero transfer length (valid) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 0); /* transfer length */ + task.transfer_len = 0; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_COMPLETE); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(task.data_transferred == 0); + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_io_queue)); + + /* zero transfer length past end of disk (invalid) */ + to_be64(&cdb[2], g_test_bdev_num_blocks); /* LBA */ + to_be32(&cdb[10], 0); /* transfer length */ + task.transfer_len = 0; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_COMPLETE); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT(task.sense_data[12] == SPDK_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE); + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_io_queue)); + + ut_put_task(&task); +} + +static void +_xfer_test(bool bdev_io_pool_full) +{ + struct spdk_bdev bdev; + struct spdk_scsi_lun lun; + struct spdk_scsi_task task; + uint8_t cdb[16]; + char data[4096]; + int rc; + + lun.bdev = &bdev; + + /* Test block device size of 512 MiB */ + g_test_bdev_num_blocks = 512 * 1024 * 1024; + + /* Read 1 block */ + ut_init_task(&task); + task.lun = &lun; + task.lun->bdev_desc = NULL; + task.lun->io_channel = NULL; + task.cdb = cdb; + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x88; /* READ (16) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 1); /* transfer length */ + task.transfer_len = 1 * 512; + g_bdev_io_pool_full = bdev_io_pool_full; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + ut_put_task(&task); + + /* Write 1 block */ + ut_init_task(&task); + task.lun = &lun; + task.cdb = cdb; + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x8a; /* WRITE (16) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 1); /* transfer length */ + task.transfer_len = 1 * 512; + g_bdev_io_pool_full = bdev_io_pool_full; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + ut_put_task(&task); + + /* Unmap 5 blocks using 2 descriptors */ + ut_init_task(&task); + task.lun = &lun; + task.cdb = cdb; + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x42; /* UNMAP */ + to_be16(&data[7], 2); /* 2 parameters in list */ + memset(data, 0, sizeof(data)); + to_be16(&data[2], 32); /* 2 descriptors */ + to_be64(&data[8], 1); /* LBA 1 */ + to_be32(&data[16], 2); /* 2 blocks */ + to_be64(&data[24], 10); /* LBA 10 */ + to_be32(&data[32], 3); /* 3 blocks */ + spdk_scsi_task_set_data(&task, data, sizeof(data)); + task.status = SPDK_SCSI_STATUS_GOOD; + g_bdev_io_pool_full = bdev_io_pool_full; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + ut_put_task(&task); + + /* Flush 1 block */ + ut_init_task(&task); + task.lun = &lun; + task.cdb = cdb; + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x91; /* SYNCHRONIZE CACHE (16) */ + to_be64(&cdb[2], 0); /* LBA */ + to_be32(&cdb[10], 1); /* 1 blocks */ + g_bdev_io_pool_full = bdev_io_pool_full; + rc = spdk_bdev_scsi_execute(&task); + CU_ASSERT(rc == SPDK_SCSI_TASK_PENDING); + CU_ASSERT(task.status == 0xFF); + + ut_bdev_io_flush(); + CU_ASSERT(task.status == SPDK_SCSI_STATUS_GOOD); + CU_ASSERT(g_scsi_cb_called == 1); + g_scsi_cb_called = 0; + ut_put_task(&task); +} + +static void +xfer_test(void) +{ + _xfer_test(false); + _xfer_test(true); +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + TAILQ_INIT(&g_bdev_io_queue); + TAILQ_INIT(&g_io_wait_queue); + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("translation_suite", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "mode select 6 test", mode_select_6_test) == NULL + || CU_add_test(suite, "mode select 6 test2", mode_select_6_test2) == NULL + || CU_add_test(suite, "mode sense 6 test", mode_sense_6_test) == NULL + || CU_add_test(suite, "mode sense 10 test", mode_sense_10_test) == NULL + || CU_add_test(suite, "inquiry evpd test", inquiry_evpd_test) == NULL + || CU_add_test(suite, "inquiry standard test", inquiry_standard_test) == NULL + || CU_add_test(suite, "inquiry overflow test", inquiry_overflow_test) == NULL + || CU_add_test(suite, "task complete test", task_complete_test) == NULL + || CU_add_test(suite, "LBA range test", lba_range_test) == NULL + || CU_add_test(suite, "transfer length test", xfer_len_test) == NULL + || CU_add_test(suite, "transfer test", xfer_test) == NULL + || CU_add_test(suite, "scsi name padding test", scsi_name_padding_test) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + return num_failures; +} |