From e93e308d3e684fd6b78f17aeef77b0642e12c247 Mon Sep 17 00:00:00 2001 From: Krishna Kanth Reddy Date: Fri, 2 Jul 2021 17:12:06 +0530 Subject: [PATCH] test/nvme: Add test application to verify Boot Partition Read / Write support Signed-off-by: Krishna Kanth Reddy Change-Id: Id26304baef0dd320ecdd4e86cb069bfe8475f6c3 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8632 Community-CI: Broadcom CI Tested-by: SPDK CI Jenkins Reviewed-by: Paul Luse Reviewed-by: Shuhei Matsumoto Reviewed-by: Aleksey Marchuk Reviewed-by: Jim Harris --- autotest.sh | 3 + test/common/autotest_common.sh | 2 + test/common/config/pkgdep/git | 1 + test/common/config/vm_setup.sh | 1 + test/common/skipped_tests.txt | 4 + test/nvme/Makefile | 2 +- test/nvme/boot_partition/.gitignore | 1 + test/nvme/boot_partition/Makefile | 38 +++ test/nvme/boot_partition/boot_partition.c | 295 ++++++++++++++++++++++ test/nvme/nvme_bp.sh | 12 + 10 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 test/nvme/boot_partition/.gitignore create mode 100644 test/nvme/boot_partition/Makefile create mode 100644 test/nvme/boot_partition/boot_partition.c create mode 100755 test/nvme/nvme_bp.sh diff --git a/autotest.sh b/autotest.sh index c0cbd3f7c..0efe738dd 100755 --- a/autotest.sh +++ b/autotest.sh @@ -216,6 +216,9 @@ if [ $SPDK_RUN_FUNCTIONAL_TEST -eq 1 ]; then if [[ $SPDK_TEST_NVME_SCC -eq 1 ]]; then run_test "nvme_scc" test/nvme/nvme_scc.sh fi + if [[ $SPDK_TEST_NVME_BP -eq 1 ]]; then + run_test "nvme_bp" test/nvme/nvme_bp.sh + fi if [[ $SPDK_TEST_NVME_CUSE -eq 1 ]]; then run_test "nvme_cuse" test/nvme/cuse/nvme_cuse.sh fi diff --git a/test/common/autotest_common.sh b/test/common/autotest_common.sh index f68dcbfe4..a6ceb2da1 100755 --- a/test/common/autotest_common.sh +++ b/test/common/autotest_common.sh @@ -91,6 +91,8 @@ export SPDK_TEST_NVME export SPDK_TEST_NVME_PMR : ${SPDK_TEST_NVME_SCC=0} export SPDK_TEST_NVME_SCC +: ${SPDK_TEST_NVME_BP=0} +export SPDK_TEST_NVME_BP : ${SPDK_TEST_NVME_CLI=0} export SPDK_TEST_NVME_CLI : ${SPDK_TEST_NVME_CUSE=0} diff --git a/test/common/config/pkgdep/git b/test/common/config/pkgdep/git index aeec9b2c8..5086c0b52 100644 --- a/test/common/config/pkgdep/git +++ b/test/common/config/pkgdep/git @@ -64,6 +64,7 @@ function install_refspdk() { SPDK_RUN_UBSAN=1 SPDK_TEST_NVME_PMR=1 SPDK_TEST_NVME_SCC=1 + SPDK_TEST_NVME_BP=1 SPDK_TEST_NVME_CUSE=1 SPDK_TEST_BLOBFS=1 SPDK_TEST_URING=1 diff --git a/test/common/config/vm_setup.sh b/test/common/config/vm_setup.sh index 59dbff6a7..445c702ee 100755 --- a/test/common/config/vm_setup.sh +++ b/test/common/config/vm_setup.sh @@ -180,6 +180,7 @@ SPDK_TEST_ISCSI_INITIATOR=1 SPDK_TEST_NVME=1 SPDK_TEST_NVME_PMR=1 SPDK_TEST_NVME_SCC=1 +SPDK_TEST_NVME_BP=1 SPDK_TEST_NVME_CLI=1 SPDK_TEST_NVMF=1 SPDK_TEST_VFIOUSER=1 diff --git a/test/common/skipped_tests.txt b/test/common/skipped_tests.txt index 9e1ab3f91..2734bbbbf 100644 --- a/test/common/skipped_tests.txt +++ b/test/common/skipped_tests.txt @@ -18,6 +18,10 @@ iscsi_tgt_fio_remote_nvme nvme_scc nvme_simple_copy +# Waiting on Boot Partition support in CI +nvme_bp +nvme_boot_partition + # Waiting on significant test rewrite nvme_opal nvme_opal_bdevio diff --git a/test/nvme/Makefile b/test/nvme/Makefile index 49f215717..d5bf97264 100644 --- a/test/nvme/Makefile +++ b/test/nvme/Makefile @@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk DIRS-y = aer reset sgl e2edp overhead deallocated_value err_injection \ - startup reserve simple_copy connect_stress + startup reserve simple_copy connect_stress boot_partition DIRS-$(CONFIG_NVME_CUSE) += cuse .PHONY: all clean $(DIRS-y) diff --git a/test/nvme/boot_partition/.gitignore b/test/nvme/boot_partition/.gitignore new file mode 100644 index 000000000..75e7aea07 --- /dev/null +++ b/test/nvme/boot_partition/.gitignore @@ -0,0 +1 @@ +boot_partition diff --git a/test/nvme/boot_partition/Makefile b/test/nvme/boot_partition/Makefile new file mode 100644 index 000000000..64c4e3d80 --- /dev/null +++ b/test/nvme/boot_partition/Makefile @@ -0,0 +1,38 @@ +# +# BSD LICENSE +# +# Copyright (c) Samsung Electronics Co., Ltd. +# 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 Samsung Electronics Co., Ltd. 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)/../../..) + +APP = boot_partition + +include $(SPDK_ROOT_DIR)/mk/nvme.libtest.mk diff --git a/test/nvme/boot_partition/boot_partition.c b/test/nvme/boot_partition/boot_partition.c new file mode 100644 index 000000000..fe410dd68 --- /dev/null +++ b/test/nvme/boot_partition/boot_partition.c @@ -0,0 +1,295 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Samsung Electronics Co., Ltd. + * 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 Samsung Electronics Co., Ltd. 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/nvme.h" +#include "spdk/util.h" +#include "spdk/env.h" + +struct ctrlr { + struct spdk_nvme_transport_id trid; + struct spdk_nvme_ctrlr *ctrlr; + char *write_buf; + char *read_buf; + int write_completed; +}; + +static struct ctrlr g_ctrlr; + +static void cleanup(void); + +static void +fill_pattern(char *buf, size_t num_bytes, char pattern) +{ + size_t i; + + for (i = 0; i < num_bytes; i++) { + buf[i] = pattern; + } +} + +static void +write_complete(void *arg, const struct spdk_nvme_cpl *completion) +{ + printf("Boot Partition Write - SCT : %d, SC : %d\n", + completion->status.sct, completion->status.sc); + g_ctrlr.write_completed = 1; +} + +static int +boot_partition_test(void) +{ + struct spdk_nvme_ctrlr *ctrlr; + union spdk_nvme_cap_register cap; + int rc; + union spdk_nvme_bpinfo_register bpinfo; + unsigned int bpsize; + unsigned int bpsize_in_4k; + + ctrlr = g_ctrlr.ctrlr; + + cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr); + + if (cap.bits.bps) { + printf("Boot Partitions are Supported by the Controller\n"); + } else { + printf("Boot Partitions are Not Supported by the Controller\n"); + return -ENOTSUP; + } + + bpinfo = spdk_nvme_ctrlr_get_regs_bpinfo(ctrlr); + bpsize = bpinfo.bits.bpsz * 131072; + bpsize_in_4k = bpsize / 4096; + + printf("Boot Partition Info\n"); + printf("Active Boot Partition ID : %d\n", bpinfo.bits.abpid); + printf("Boot Read Status : %d\n", bpinfo.bits.brs); + printf("Boot Partition Size : %d bytes\n", bpsize); + + g_ctrlr.write_buf = spdk_zmalloc(bpsize, 0x1000, NULL, + SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); + + if (g_ctrlr.write_buf == NULL) { + printf("Error - could not allocate write buffer for test\n"); + cleanup(); + return -ENOMEM; + } + + g_ctrlr.read_buf = spdk_memzone_reserve("boot_partition", bpsize, + SPDK_ENV_SOCKET_ID_ANY, 0); + + if (g_ctrlr.read_buf == NULL) { + printf("Error - could not allocate read buffer for test\n"); + cleanup(); + return -ENOMEM; + } + + fill_pattern(g_ctrlr.write_buf, bpsize, 0xDE); + + g_ctrlr.write_completed = 0; + rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf, + bpsize, 0, write_complete, NULL); + if (rc) { + printf("Error - Boot Partition write failure. rc: %d", rc); + cleanup(); + return rc; + } + + while (!g_ctrlr.write_completed) { + spdk_nvme_ctrlr_process_admin_completions(ctrlr); + } + + rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf, + bpsize_in_4k, 0, 0); + + if (rc) { + printf("Error - Boot Partition read start failure. rc: %d", rc); + cleanup(); + return rc; + } + + do { + rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr); + } while (rc == -EAGAIN); + + if (rc != 0) { + printf("Error - Boot Partition read poll failure. rc: %d", rc); + cleanup(); + return rc; + } + + rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize); + if (rc) { + printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc); + cleanup(); + return rc; + } + + printf("Boot Partition 0 written data matches Boot Partition 0 read data\n"); + + fill_pattern(g_ctrlr.write_buf, bpsize, 0xAD); + + g_ctrlr.write_completed = 0; + rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf, + bpsize, 1, write_complete, NULL); + if (rc) { + printf("Error - Boot Partition write failure. rc: %d", rc); + cleanup(); + return rc; + } + + while (!g_ctrlr.write_completed) { + spdk_nvme_ctrlr_process_admin_completions(ctrlr); + } + + rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf, + bpsize_in_4k, 0, 1); + + if (rc) { + printf("Error - Boot Partition read start failure. rc: %d", rc); + cleanup(); + return rc; + } + + do { + rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr); + } while (rc == -EAGAIN); + + if (rc != 0) { + printf("Error - Boot Partition read poll failure. rc: %d", rc); + cleanup(); + return rc; + } + + rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize); + if (rc) { + printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc); + cleanup(); + return rc; + } + + printf("Boot Partition 1 written data matches Boot Partition 1 read data\n"); + + cleanup(); + + return 0; +} + +static void +cleanup(void) +{ + spdk_memzone_free("boot_partition"); + spdk_free(g_ctrlr.write_buf); + spdk_nvme_detach(g_ctrlr.ctrlr); +} + +static void +usage(char *program_name) +{ + printf("%s Option (Mandatory)", program_name); + printf("\n"); + printf("\t[-p PCIe address of the NVMe Device with Boot Partition support]\n"); + printf("\n"); +} + +static int +parse_args(int argc, char **argv) +{ + int op; + unsigned num_args = 0; + + while ((op = getopt(argc, argv, "p:")) != -1) { + switch (op) { + case 'p': + snprintf(&g_ctrlr.trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1, + "%s", optarg); + + g_ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE; + + spdk_nvme_transport_id_populate_trstring(&g_ctrlr.trid, + spdk_nvme_transport_id_trtype_str(g_ctrlr.trid.trtype)); + + num_args++; + break; + default: + usage(argv[0]); + return 1; + } + } + + if (num_args != 1) { + usage(argv[0]); + return 1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int rc; + struct spdk_env_opts opts; + + /* + * Parse the input arguments. For now we use the following + * format list: + * + * -p + * + */ + rc = parse_args(argc, argv); + if (rc) { + fprintf(stderr, "Error in parse_args(): %d\n", rc); + return rc; + } + + spdk_env_opts_init(&opts); + opts.name = "boot_partition"; + opts.shm_id = 0; + if (spdk_env_init(&opts) < 0) { + fprintf(stderr, "Unable to initialize SPDK env\n"); + return 1; + } + + printf("Initializing NVMe Controller\n"); + + g_ctrlr.ctrlr = spdk_nvme_connect(&g_ctrlr.trid, NULL, 0); + if (!g_ctrlr.ctrlr) { + fprintf(stderr, "spdk_nvme_connect() failed\n"); + return 1; + } + + printf("Initialization complete.\n"); + rc = boot_partition_test(); + return rc; +} diff --git a/test/nvme/nvme_bp.sh b/test/nvme/nvme_bp.sh new file mode 100755 index 000000000..dc6b70718 --- /dev/null +++ b/test/nvme/nvme_bp.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/scripts/common.sh +source $rootdir/test/common/autotest_common.sh + +if [ $(uname) = Linux ]; then + $rootdir/scripts/setup.sh +fi + +run_test "nvme_boot_partition" $testdir/boot_partition/boot_partition