# SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of nvme-cli # # Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. # # Authors: Arunpandian J # Joy Gu """ NVMe Copy Testcase:- 1. Issue copy command on set of block; shall pass. 2. If cross-namespace copy formats are supported, enable and test cross-namespace copy formats. """ import subprocess from nvme_test import TestNVMe class TestNVMeCopy(TestNVMe): """ Represents NVMe Copy testcase. - Attributes: - ocfs : optional copy formats supported - host_behavior_data : host behavior support data to restore during teardown - test_log_dir : directory for logs, temp files. """ def setUp(self): """ Pre Section for TestNVMeCopy """ super().setUp() self.ocfs = self.get_ocfs() self.host_behavior_data = None cross_namespace_copy = self.ocfs & 0xc if cross_namespace_copy: # get host behavior support data get_features_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \ "--feature-id=0x16 --data-len=512 --raw-binary" proc = subprocess.Popen(get_features_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') err = proc.wait() self.assertEqual(err, 0, "ERROR : nvme get-feature failed") self.host_behavior_data = proc.stdout.read() # enable cross-namespace copy formats if self.host_behavior_data[4] & cross_namespace_copy: # skip if already enabled print("Cross-namespace copy already enabled, skipping set-features") self.host_behavior_data = None else: data = self.host_behavior_data[:4] + cross_namespace_copy.to_bytes(2, 'little') + self.host_behavior_data[6:] set_features_cmd = f"{self.nvme_bin} set-feature " + \ f"{self.ctrl} --feature-id=0x16 --data-len=512" proc = subprocess.Popen(set_features_cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, encoding='utf-8') proc.communicate(input=data) self.assertEqual(proc.returncode, 0, "Failed to enable cross-namespace copy formats") get_ns_id_cmd = f"{self.nvme_bin} get-ns-id {self.ns1}" proc = subprocess.Popen(get_ns_id_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') err = proc.wait() self.assertEqual(err, 0, "ERROR : nvme get-ns-id failed") output = proc.stdout.read() self.ns1_nsid = int(output.strip().split(':')[-1]) self.setup_log_dir(self.__class__.__name__) def tearDown(self): """ Post Section for TestNVMeCopy """ if self.host_behavior_data: # restore saved host behavior support data set_features_cmd = f"{self.nvme_bin} set-feature {self.ctrl} " + \ "--feature-id=0x16 --data-len=512" proc = subprocess.Popen(set_features_cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, encoding='utf-8') proc.communicate(input=self.host_behavior_data) super().tearDown() def copy(self, sdlba, blocks, slbs, **kwargs): """ Wrapper for nvme copy - Args: - sdlba : destination logical block address - blocks : number of logical blocks (0-based) - slbs : source range logical block address - descriptor_format : copy descriptor format (optional) - snsids : source namespace id (optional) - sopts : source options (optional) - Returns: - None """ # skip if descriptor format not supported (default format is 0) desc_format = kwargs.get("descriptor_format", 0) if not self.ocfs & (1 << desc_format): print(f"Skip copy because descriptor format {desc_format} is not supported") return # build copy command copy_cmd = f"{self.nvme_bin} copy {self.ns1} " + \ f"--format={desc_format} --sdlba={sdlba} --blocks={blocks} " + \ f"--slbs={slbs}" if "snsids" in kwargs: copy_cmd += f" --snsids={kwargs['snsids']}" if "sopts" in kwargs: copy_cmd += f" --sopts={kwargs['sopts']}" # run and assert success self.assertEqual(self.exec_cmd(copy_cmd), 0) def test_copy(self): """ Testcase main """ self.copy(0, 1, 2, descriptor_format=0) self.copy(0, 1, 2, descriptor_format=1) self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid) self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid, sopts=0) self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid) self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid, sopts=0)