1
0
Fork 0

Merging upstream version 2.12.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-20 08:10:44 +01:00
parent 078c0dbcc0
commit 635faa7346
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
571 changed files with 10718 additions and 2738 deletions

View file

@ -29,8 +29,6 @@ NVMe Namespace Management Testcase:-
5. Delete Namespace.
"""
import time
from nvme_test import TestNVMe
@ -59,7 +57,6 @@ class TestNVMeAttachDetachNSCmd(TestNVMe):
self.setup_log_dir(self.__class__.__name__)
self.ctrl_id = self.get_ctrl_id()
self.delete_all_ns()
time.sleep(1)
def tearDown(self):
"""

View file

@ -30,6 +30,7 @@ NVMe Compare Command Testcase:-
"""
from nvme_test import to_decimal
from nvme_test_io import TestNVMeIO
@ -52,7 +53,7 @@ class TestNVMeCompareCmd(TestNVMeIO):
- Returns:
- True if 'compare' is supported, otherwise False
"""
return int(self.get_id_ctrl_field_value("oncs"), 16) & (1 << 0)
return to_decimal(self.get_id_ctrl_field_value("oncs")) & (1 << 0)
def setUp(self):
""" Pre Section for TestNVMeCompareCmd """
@ -78,10 +79,10 @@ class TestNVMeCompareCmd(TestNVMeIO):
- Returns:
- return code of the nvme compare command.
"""
compare_cmd = "nvme compare " + self.ns1 + " --start-block=" + \
str(self.start_block) + " --block-count=" + \
str(self.block_count) + " --data-size=" + \
str(self.data_size) + " --data=" + cmp_file
compare_cmd = f"{self.nvme_bin} compare {self.ns1} " + \
f"--start-block={str(self.start_block)} " + \
f"--block-count={str(self.block_count)} " + \
f"--data-size={str(self.data_size)} --data={cmp_file}"
return self.exec_cmd(compare_cmd)
def test_nvme_compare(self):

View file

@ -34,15 +34,20 @@ class TestNVMeCopy(TestNVMe):
def setUp(self):
""" Pre Section for TestNVMeCopy """
super().setUp()
print("\nSetting up test...")
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 = ["nvme", "get-feature", self.ctrl, "--feature-id=0x16", "--data-len=512", "-b"]
print("Running command:", " ".join(get_features_cmd))
self.host_behavior_data = subprocess.check_output(get_features_cmd)
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
@ -50,29 +55,37 @@ class TestNVMeCopy(TestNVMe):
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 = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"]
print("Running command:", " ".join(set_features_cmd))
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)
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 = ["nvme", "get-ns-id", self.ns1]
print("Running command:", " ".join(get_ns_id_cmd))
output = subprocess.check_output(get_ns_id_cmd)
self.ns1_nsid = int(output.decode().strip().split(':')[-1])
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 """
print("Tearing down test...")
if self.host_behavior_data:
# restore saved host behavior support data
set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"]
print("Running command:", " ".join(set_features_cmd))
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)
stdin=subprocess.PIPE,
encoding='utf-8')
proc.communicate(input=self.host_behavior_data)
super().tearDown()
@ -94,18 +107,18 @@ class TestNVMeCopy(TestNVMe):
print(f"Skip copy because descriptor format {desc_format} is not supported")
return
# build copy command
copy_cmd = f"nvme copy {self.ns1} --format={desc_format} --sdlba={sdlba} --blocks={blocks} --slbs={slbs}"
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
print("Running command:", copy_cmd)
self.assertEqual(self.exec_cmd(copy_cmd), 0)
def test_copy(self):
""" Testcase main """
print("Running test...")
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)

View file

@ -29,8 +29,6 @@ NVMe Namespace Management Testcase:-
5. Delete all Namespaces.
"""
import time
from nvme_test import TestNVMe
@ -52,8 +50,9 @@ class TestNVMeCreateMaxNS(TestNVMe):
super().setUp()
self.dps = 0
self.flbas = 0
(ds, ms) = self.get_lba_format_size()
self.nsze = int(self.get_ncap() /
self.get_format() / self.get_max_ns())
(ds + ms) / self.get_max_ns())
# Make sure that we have enough capacity for each ns.
# Creating a ns might allocate more bits (NVMCAP) than specified by
# nsze and ncap.
@ -63,7 +62,6 @@ class TestNVMeCreateMaxNS(TestNVMe):
self.max_ns = self.get_max_ns()
self.ctrl_id = self.get_ctrl_id()
self.delete_all_ns()
time.sleep(1)
def tearDown(self):
"""
@ -85,21 +83,21 @@ class TestNVMeCreateMaxNS(TestNVMe):
""" Testcase main """
print(f"##### Testing max_ns: {self.max_ns}")
for nsid in range(1, self.max_ns + 1):
print("##### Creating " + str(nsid))
print(f"##### Creating {nsid}")
err = self.create_and_validate_ns(nsid,
self.nsze,
self.ncap,
self.flbas,
self.dps)
self.assertEqual(err, 0)
print("##### Attaching " + str(nsid))
print(f"##### Attaching {nsid}")
self.assertEqual(self.attach_ns(self.ctrl_id, nsid), 0)
print("##### Running IOs in " + str(nsid))
print(f"##### Running IOs in {nsid}")
self.run_ns_io(nsid, 9, 1)
for nsid in range(1, self.max_ns + 1):
print("##### Detaching " + str(nsid))
print(f"##### Detaching {nsid}")
self.assertEqual(self.detach_ns(self.ctrl_id, nsid), 0)
print("#### Deleting " + str(nsid))
print(f"#### Deleting {nsid}")
self.assertEqual(self.delete_and_validate_ns(nsid), 0)
self.nvme_reset_ctrl()

View file

@ -40,7 +40,7 @@ class TestNVMeCtrlReset(TestNVMe):
- Returns:
- return code for nvme controller reset.
"""
ctrl_reset_cmd = "nvme reset " + self.ctrl
ctrl_reset_cmd = f"{self.nvme_bin} reset {self.ctrl}"
return self.exec_cmd(ctrl_reset_cmd)
def test_ctrl_reset(self):

View file

@ -45,10 +45,9 @@ class TestNVMeDsm(TestNVMe):
- Returns:
- return code for nvme dsm command.
"""
dsm_cmd = "nvme dsm " + self.ctrl + \
" --namespace-id=" + str(self.namespace) + \
" --blocks=" + str(self.range) + \
" --slbs=" + str(self.start_block)
dsm_cmd = f"{self.nvme_bin} dsm {self.ctrl} " + \
f"--namespace-id={str(self.namespace)} " + \
f"--blocks={str(self.range)} --slbs={str(self.start_block)}"
return self.exec_cmd(dsm_cmd)
def test_dsm(self):

View file

@ -53,8 +53,8 @@ class TestNVMeFlushCmd(TestNVMe):
- Returns:
- None
"""
flush_cmd = "nvme flush " + self.ctrl + " -n " + str(self.default_nsid)
print(flush_cmd)
flush_cmd = f"{self.nvme_bin} flush {self.ctrl} " + \
f"--namespace-id={str(self.default_nsid)}"
return self.exec_cmd(flush_cmd)
def test_nvme_flush(self):

View file

@ -37,9 +37,9 @@ Namespace Format testcase :-
- Delete Namespace.
"""
import json
import math
import subprocess
import time
from nvme_test import TestNVMe
@ -55,9 +55,7 @@ class TestNVMeFormatCmd(TestNVMe):
- nsze : namespace size.
- ncap : namespace capacity.
- ctrl_id : controller id.
- lba_format_list : lis of supported format.
- ms_list : list of metadat size per format.
- lbads_list : list of LBA data size per format.
- lba_format_list : json list of supported format.
- test_log_dir : directory for logs, temp files.
"""
@ -74,12 +72,9 @@ class TestNVMeFormatCmd(TestNVMe):
self.nsze = ncap
self.ctrl_id = self.get_ctrl_id()
self.lba_format_list = []
self.ms_list = []
self.lbads_list = []
self.test_log_dir = self.log_dir + "/" + self.__class__.__name__
self.setup_log_dir(self.__class__.__name__)
self.delete_all_ns()
time.sleep(1)
def tearDown(self):
"""
@ -106,50 +101,44 @@ class TestNVMeFormatCmd(TestNVMe):
self.dps), 0)
self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
# read lbaf information
id_ns = "nvme id-ns " + self.ctrl + \
" -n1 | grep ^lbaf | awk '{print $2}' | tr -s \"\\n\" \" \""
proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE,
id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \
f"--namespace-id={self.default_nsid} --output-format=json"
proc = subprocess.Popen(id_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
self.lba_format_list = proc.stdout.read().strip().split(" ")
if proc.wait() == 0:
# read lbads information
id_ns = "nvme id-ns " + self.ctrl + \
" -n1 | grep ^lbaf | awk '{print $5}'" + \
" | cut -f 2 -d ':' | tr -s \"\\n\" \" \""
proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE,
encoding='utf-8')
self.lbads_list = proc.stdout.read().strip().split(" ")
# read metadata information
id_ns = "nvme id-ns " + self.ctrl + \
" -n1 | grep ^lbaf | awk '{print $4}'" + \
" | cut -f 2 -d ':' | tr -s \"\\n\" \" \""
proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE,
encoding='utf-8')
self.ms_list = proc.stdout.read().strip().split(" ")
self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0)
self.nvme_reset_ctrl()
err = proc.wait()
self.assertEqual(err, 0, "ERROR : nvme id-ns failed")
json_output = json.loads(proc.stdout.read())
self.lba_format_list = json_output['lbafs']
self.assertTrue(len(self.lba_format_list) > 0,
"ERROR : nvme id-ns could not find any lba formats")
self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0)
self.nvme_reset_ctrl()
def test_format_ns(self):
""" Testcase main """
# extract the supported format information.
self.attach_detach_primary_ns()
print("##### Testing lba formats:")
# iterate through all supported format
for i in range(0, len(self.lba_format_list)):
print("\nlba format " + str(self.lba_format_list[i]) +
" lbad " + str(self.lbads_list[i]) +
" ms " + str(self.ms_list[i]))
metadata_size = 1 if self.ms_list[i] == '8' else 0
for flbas, lba_format in enumerate(self.lba_format_list):
ds = lba_format['ds']
ms = lba_format['ms']
print(f"\nlba format {str(flbas)}"
f"\nds {str(ds)}"
f"\nms {str(ms)}")
dps = 1 if str(ms) == '8' else 0
err = self.create_and_validate_ns(self.default_nsid,
self.nsze,
self.ncap,
self.lba_format_list[i],
metadata_size)
flbas,
dps)
self.assertEqual(err, 0)
self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
self.run_ns_io(self.default_nsid, self.lbads_list[i])
time.sleep(5)
self.run_ns_io(self.default_nsid, int(ds))
self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0)
self.nvme_reset_ctrl()

View file

@ -57,16 +57,12 @@ class TestNVMeFwLogCmd(TestNVMe):
- Returns:
- 0 on success, error code on failure.
"""
err = 0
fw_log_cmd = "nvme fw-log " + self.ctrl
fw_log_cmd = f"{self.nvme_bin} fw-log {self.ctrl}"
proc = subprocess.Popen(fw_log_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
fw_log_output = proc.communicate()[0]
print("\n" + fw_log_output + "\n")
err = proc.wait()
return err
return proc.wait()
def test_fw_log(self):
""" Testcase main """

View file

@ -81,27 +81,23 @@ class TestNVMeGetMandatoryFeatures(TestNVMe):
"""
if str(feature_id) == "0x09":
for vector in range(self.vector_list_len):
get_feat_cmd = "nvme get-feature " + self.ctrl + \
" --feature-id=" + str(feature_id) + \
" --cdw11=" + str(vector) + " -H"
get_feat_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \
f"--feature-id={str(feature_id)} " + \
f"--cdw11={str(vector)} --human-readable"
proc = subprocess.Popen(get_feat_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
feature_output = proc.communicate()[0]
print(feature_output)
self.assertEqual(proc.wait(), 0)
else:
get_feat_cmd = "nvme get-feature " + self.ctrl + \
" --feature-id=" + str(feature_id) + " -H"
get_feat_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \
f"--feature-id={str(feature_id)} --human-readable"
if str(feature_id) == "0x05":
get_feat_cmd += f" --namespace-id={self.default_nsid}"
proc = subprocess.Popen(get_feat_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
feature_output = proc.communicate()[0]
print(feature_output)
self.assertEqual(proc.wait(), 0)
def test_get_mandatory_features(self):

View file

@ -50,21 +50,17 @@ class TestNVMeGetLbaStatusCmd(TestNVMe):
- Returns:
- 0 on success, error code on failure.
"""
err = 0
get_lba_status_cmd = "nvme get-lba-status " + self.ctrl + \
" --namespace-id=" + str(self.ns1) + \
" --start-lba=" + str(self.start_lba) + \
" --max-dw=" + str(self.max_dw) + \
" --action=" + str(self.action) + \
" --range-len=" + str(self.range_len)
get_lba_status_cmd = f"{self.nvme_bin} get-lba-status {self.ctrl} " + \
f"--namespace-id={str(self.ns1)} " + \
f"--start-lba={str(self.start_lba)} " + \
f"--max-dw={str(self.max_dw)} " + \
f"--action={str(self.action)} " + \
f"--range-len={str(self.range_len)}"
proc = subprocess.Popen(get_lba_status_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
get_lba_status_output = proc.communicate()[0]
print("\n" + get_lba_status_output + "\n")
err = proc.wait()
return err
return proc.wait()
def test_get_lba_status(self):
""" Testcase main """

View file

@ -42,7 +42,7 @@ class TestNVMeIdentifyNamespace(TestNVMe):
""" Pre Section for TestNVMeIdentifyNamespace. """
super().setUp()
self.setup_log_dir(self.__class__.__name__)
self.ns_list = self.get_ns_list()
self.nsid_list = self.get_nsid_list()
def tearDown(self):
"""
@ -60,16 +60,13 @@ class TestNVMeIdentifyNamespace(TestNVMe):
- Returns:
- 0 on success, error code on failure.
"""
err = 0
id_ns_cmd = "nvme id-ns " + self.ctrl + "n" + str(nsid)
id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \
f"--namespace-id={str(nsid)}"
proc = subprocess.Popen(id_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
id_ns_output = proc.communicate()[0]
print(id_ns_output + "\n")
err = proc.wait()
return err
return proc.wait()
def get_id_ns_all(self):
"""
@ -80,7 +77,7 @@ class TestNVMeIdentifyNamespace(TestNVMe):
- 0 on success, error code on failure.
"""
err = 0
for namespace in self.ns_list:
for namespace in self.nsid_list:
err = self.get_id_ns(str(namespace))
return err

View file

@ -45,16 +45,12 @@ class TestNVMeLbaStatLogCmd(TestNVMe):
- Returns:
- 0 on success, error code on failure.
"""
err = 0
lba_stat_log_cmd = "nvme lba-status-log " + self.ctrl
lba_stat_log_cmd = f"{self.nvme_bin} lba-status-log {self.ctrl}"
proc = subprocess.Popen(lba_stat_log_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
lba_stat_log_output = proc.communicate()[0]
print("\n" + lba_stat_log_output + "\n")
err = proc.wait()
return err
return proc.wait()
def test_lba_stat_log(self):
""" Testcase main """

View file

@ -27,7 +27,7 @@ NVMe Smart Log Verification Testcase:-
"""
from nvme_test import TestNVMe
from nvme_test import TestNVMe, to_decimal
class TestNVMeSmartLogCmd(TestNVMe):
@ -76,14 +76,14 @@ class TestNVMeSmartLogCmd(TestNVMe):
- Returns:
- 0 on success, error code on failure.
"""
ns_list = self.get_ns_list()
for nsid in range(0, len(ns_list)):
self.get_smart_log_ns(ns_list[nsid])
nsid_list = self.get_nsid_list()
for nsid in nsid_list:
self.get_smart_log_ns(nsid)
return 0
def test_smart_log(self):
""" Testcase main """
self.assertEqual(self.get_smart_log_ctrl(), 0)
smlp = self.supp_check_id_ctrl("lpa")
smlp = to_decimal(self.get_id_ctrl_field_value("lpa"))
if smlp & 0x1:
self.assertEqual(self.get_smart_log_all_ns(), 0)

View file

@ -30,12 +30,22 @@ import shutil
import stat
import subprocess
import sys
import time
import unittest
import time
from nvme_test_logger import TestNVMeLogger
def to_decimal(value):
""" Wrapper for converting numbers to base 10 decimal
- Args:
- value: A number in any common base
- Returns:
- Decimal integer
"""
return int(str(value), 0)
class TestNVMe(unittest.TestCase):
"""
@ -58,19 +68,28 @@ class TestNVMe(unittest.TestCase):
self.ctrl = "XXX"
self.ns1 = "XXX"
self.test_log_dir = "XXX"
self.nvme_bin = "nvme"
self.do_validate_pci_device = True
self.default_nsid = 0x1
self.flbas = 0
self.config_file = 'tests/config.json'
self.load_config()
if self.do_validate_pci_device:
self.validate_pci_device()
self.create_and_attach_default_ns()
print(f"\nsetup: ctrl: {self.ctrl}, ns1: {self.ns1}, default_nsid: {self.default_nsid}, flbas: {self.flbas}\n")
def tearDown(self):
""" Post Section for TestNVMe. """
if self.clear_log_dir is True:
shutil.rmtree(self.log_dir, ignore_errors=True)
self.create_and_attach_default_ns()
print(f"\nteardown: ctrl: {self.ctrl}, ns1: {self.ns1}, default_nsid: {self.default_nsid}, flbas: {self.flbas}\n")
@classmethod
def tearDownClass(cls):
print("\n")
def create_and_attach_default_ns(self):
""" Creates a default namespace with the full capacity of the ctrls NVM
@ -103,8 +122,8 @@ class TestNVMe(unittest.TestCase):
- None
"""
x1, x2, dev = self.ctrl.split('/')
cmd = cmd = "find /sys/devices -name \\*" + dev + " | grep -i pci"
err = subprocess.call(cmd, shell=True)
cmd = "find /sys/devices -name \\*" + dev + " | grep -i pci"
err = subprocess.call(cmd, shell=True, stdout=subprocess.DEVNULL)
self.assertEqual(err, 0, "ERROR : Only NVMe PCI subsystem is supported")
def load_config(self):
@ -119,7 +138,10 @@ class TestNVMe(unittest.TestCase):
self.ctrl = config['controller']
self.ns1 = config['ns1']
self.log_dir = config['log_dir']
self.do_validate_pci_device = config.get('do_validate_pci_device', self.do_validate_pci_device)
self.nvme_bin = config.get('nvme_bin', self.nvme_bin)
print(f"\nUsing nvme binary '{self.nvme_bin}'")
self.do_validate_pci_device = config.get(
'do_validate_pci_device', self.do_validate_pci_device)
self.clear_log_dir = False
if self.clear_log_dir is True:
@ -154,20 +176,17 @@ class TestNVMe(unittest.TestCase):
- Returns:
- None
"""
nvme_reset_cmd = "nvme reset " + self.ctrl
nvme_reset_cmd = f"{self.nvme_bin} reset {self.ctrl}"
err = subprocess.call(nvme_reset_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
stdout=subprocess.DEVNULL)
self.assertEqual(err, 0, "ERROR : nvme reset failed")
time.sleep(5)
rescan_cmd = "echo 1 > /sys/bus/pci/rescan"
proc = subprocess.Popen(rescan_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='utf-8')
time.sleep(5)
self.assertEqual(proc.wait(), 0, "ERROR : pci rescan failed")
def get_ctrl_id(self):
@ -177,7 +196,8 @@ class TestNVMe(unittest.TestCase):
- Returns:
- controller id.
"""
get_ctrl_id = f"nvme list-ctrl {self.ctrl} --output-format=json"
get_ctrl_id = f"{self.nvme_bin} list-ctrl {self.ctrl} " + \
"--output-format=json"
proc = subprocess.Popen(get_ctrl_id,
shell=True,
stdout=subprocess.PIPE,
@ -189,7 +209,7 @@ class TestNVMe(unittest.TestCase):
"ERROR : nvme list-ctrl could not find ctrl")
return str(json_output['ctrl_list'][0]['ctrl_id'])
def get_ns_list(self):
def get_nsid_list(self):
""" Wrapper for extracting the namespace list.
- Args:
- None
@ -197,14 +217,17 @@ class TestNVMe(unittest.TestCase):
- List of the namespaces.
"""
ns_list = []
ns_list_cmd = "nvme list-ns " + self.ctrl
ns_list_cmd = f"{self.nvme_bin} list-ns {self.ctrl} " + \
"--output-format=json"
proc = subprocess.Popen(ns_list_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
self.assertEqual(proc.wait(), 0, "ERROR : nvme list namespace failed")
for line in proc.stdout:
ns_list.append(line.split('x')[-1])
json_output = json.loads(proc.stdout.read())
for ns in json_output['nsid_list']:
ns_list.append(ns['nsid'])
return ns_list
@ -215,22 +238,16 @@ class TestNVMe(unittest.TestCase):
- Returns:
- maximum number of namespaces supported.
"""
pattern = re.compile("^nn[ ]+: [0-9]", re.IGNORECASE)
max_ns = -1
max_ns_cmd = "nvme id-ctrl " + self.ctrl
max_ns_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl} " + \
"--output-format=json"
proc = subprocess.Popen(max_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
err = proc.wait()
self.assertEqual(err, 0, "ERROR : reading maximum namespace count failed")
for line in proc.stdout:
if pattern.match(line):
max_ns = line.split(":")[1].strip()
break
print(max_ns)
return int(max_ns)
json_output = json.loads(proc.stdout.read())
return int(json_output['nn'])
def get_lba_status_supported(self):
""" Check if 'Get LBA Status' command is supported by the device
@ -239,7 +256,7 @@ class TestNVMe(unittest.TestCase):
- Returns:
- True if 'Get LBA Status' command is supported, otherwise False
"""
return int(self.get_id_ctrl_field_value("oacs"), 16) & (1 << 9)
return to_decimal(self.get_id_ctrl_field_value("oacs")) & (1 << 9)
def get_lba_format_size(self):
""" Wrapper for extracting lba format size of the given flbas
@ -248,7 +265,8 @@ class TestNVMe(unittest.TestCase):
- Returns:
- lba format size as a tuple of (data_size, metadata_size) in bytes.
"""
nvme_id_ns_cmd = f"nvme id-ns {self.ns1} --output-format=json"
nvme_id_ns_cmd = f"{self.nvme_bin} id-ns {self.ns1} " + \
"--output-format=json"
proc = subprocess.Popen(nvme_id_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
@ -274,24 +292,9 @@ class TestNVMe(unittest.TestCase):
- Args:
- None
- Returns:
- maximum number of namespaces supported.
- Total NVM capacity.
"""
pattern = re.compile("^tnvmcap[ ]+: [0-9]", re.IGNORECASE)
ncap = -1
ncap_cmd = "nvme id-ctrl " + self.ctrl
proc = subprocess.Popen(ncap_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
err = proc.wait()
self.assertEqual(err, 0, "ERROR : reading nvm capacity failed")
for line in proc.stdout:
if pattern.match(line):
ncap = line.split(":")[1].strip()
break
print(ncap)
return int(ncap)
return to_decimal(self.get_id_ctrl_field_value("tnvmcap"))
def get_id_ctrl_field_value(self, field):
""" Wrapper for extracting id-ctrl field values
@ -300,7 +303,8 @@ class TestNVMe(unittest.TestCase):
- Returns:
- Filed value of the given field
"""
id_ctrl_cmd = f"nvme id-ctrl {self.ctrl} --output-format=json"
id_ctrl_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl} " + \
"--output-format=json"
proc = subprocess.Popen(id_ctrl_cmd,
shell=True,
stdout=subprocess.PIPE,
@ -319,30 +323,7 @@ class TestNVMe(unittest.TestCase):
- Returns:
- Optional Copy Formats Supported
"""
return int(self.get_id_ctrl_field_value("ocfs"), 16)
def get_format(self):
""" Wrapper for extracting format.
- Args:
- None
- Returns:
- maximum format of namespace.
"""
# defaulting to 4K
nvm_format = 4096
nvm_format_cmd = "nvme id-ns " + self.ctrl + " -n1"
proc = subprocess.Popen(nvm_format_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
err = proc.wait()
self.assertEqual(err, 0, "ERROR : reading nvm capacity failed")
for line in proc.stdout:
if "in use" in line:
nvm_format = 2 ** int(line.split(":")[3].split()[0])
print(nvm_format)
return int(nvm_format)
return to_decimal(self.get_id_ctrl_field_value("ocfs"))
def delete_all_ns(self):
""" Wrapper for deleting all the namespaces.
@ -351,15 +332,19 @@ class TestNVMe(unittest.TestCase):
- Returns:
- None
"""
delete_ns_cmd = "nvme delete-ns " + self.ctrl + " -n 0xFFFFFFFF"
delete_ns_cmd = f"{self.nvme_bin} delete-ns {self.ctrl} " + \
"--namespace-id=0xFFFFFFFF"
self.assertEqual(self.exec_cmd(delete_ns_cmd), 0)
list_ns_cmd = "nvme list-ns " + self.ctrl + " --all | wc -l"
list_ns_cmd = f"{self.nvme_bin} list-ns {self.ctrl} --all " + \
"--output-format=json"
proc = subprocess.Popen(list_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
output = proc.stdout.read().strip()
self.assertEqual(output, '0', "ERROR : deleting all namespace failed")
self.assertEqual(proc.wait(), 0, "ERROR : nvme list-ns failed")
json_output = json.loads(proc.stdout.read())
self.assertEqual(len(json_output['nsid_list']), 0,
"ERROR : deleting all namespace failed")
def create_ns(self, nsze, ncap, flbas, dps):
""" Wrapper for creating a namespace.
@ -371,9 +356,9 @@ class TestNVMe(unittest.TestCase):
- Returns:
- return code of the nvme create namespace command.
"""
create_ns_cmd = "nvme create-ns " + self.ctrl + " --nsze=" + \
str(nsze) + " --ncap=" + str(ncap) + \
" --flbas=" + str(flbas) + " --dps=" + str(dps)
create_ns_cmd = f"{self.nvme_bin} create-ns {self.ctrl} " + \
f"--nsze={str(nsze)} --ncap={str(ncap)} --flbas={str(flbas)} " + \
f"--dps={str(dps)} --verbose"
return self.exec_cmd(create_ns_cmd)
def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps):
@ -389,15 +374,14 @@ class TestNVMe(unittest.TestCase):
"""
err = self.create_ns(nsze, ncap, flbas, dps)
if err == 0:
time.sleep(2)
id_ns_cmd = "nvme id-ns " + self.ctrl + " -n " + str(nsid)
id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \
f"--namespace-id={str(nsid)}"
err = subprocess.call(id_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
stdout=subprocess.DEVNULL)
return err
def attach_ns(self, ctrl_id, ns_id):
def attach_ns(self, ctrl_id, nsid):
""" Wrapper for attaching the namespace.
- Args:
- ctrl_id : controller id to which namespace to be attached.
@ -405,21 +389,23 @@ class TestNVMe(unittest.TestCase):
- Returns:
- 0 on success, error code on failure.
"""
attach_ns_cmd = "nvme attach-ns " + self.ctrl + \
" --namespace-id=" + str(ns_id) + \
" --controllers=" + ctrl_id
attach_ns_cmd = f"{self.nvme_bin} attach-ns {self.ctrl} " + \
f"--namespace-id={str(nsid)} --controllers={ctrl_id} --verbose"
err = subprocess.call(attach_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
time.sleep(5)
if err == 0:
# enumerate new namespace block device
self.nvme_reset_ctrl()
time.sleep(5)
# check if new namespace block device exists
err = 0 if stat.S_ISBLK(os.stat(self.ns1).st_mode) else 1
return err
stdout=subprocess.DEVNULL)
if err != 0:
return err
# Try to find block device for 5 seconds
device_path = f"{self.ctrl}n{str(nsid)}"
stop_time = time.time() + 5
while time.time() < stop_time:
if os.path.exists(device_path) and stat.S_ISBLK(os.stat(device_path).st_mode):
return 0
time.sleep(0.1)
return 1
def detach_ns(self, ctrl_id, nsid):
""" Wrapper for detaching the namespace.
@ -429,13 +415,11 @@ class TestNVMe(unittest.TestCase):
- Returns:
- 0 on success, error code on failure.
"""
detach_ns_cmd = "nvme detach-ns " + self.ctrl + \
" --namespace-id=" + str(nsid) + \
" --controllers=" + ctrl_id
detach_ns_cmd = f"{self.nvme_bin} detach-ns {self.ctrl} " + \
f"--namespace-id={str(nsid)} --controllers={ctrl_id} --verbose"
return subprocess.call(detach_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
stdout=subprocess.DEVNULL)
def delete_and_validate_ns(self, nsid):
""" Wrapper for deleting and validating that namespace is deleted.
@ -445,11 +429,11 @@ class TestNVMe(unittest.TestCase):
- 0 on success, 1 on failure.
"""
# delete the namespace
delete_ns_cmd = "nvme delete-ns " + self.ctrl + " -n " + str(nsid)
delete_ns_cmd = f"{self.nvme_bin} delete-ns {self.ctrl} " + \
f"--namespace-id={str(nsid)} --verbose"
err = subprocess.call(delete_ns_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
stdout=subprocess.DEVNULL)
self.assertEqual(err, 0, "ERROR : delete namespace failed")
return err
@ -460,16 +444,14 @@ class TestNVMe(unittest.TestCase):
- Returns:
- 0 on success, error code on failure.
"""
smart_log_cmd = "nvme smart-log " + self.ctrl + " -n " + str(nsid)
print(smart_log_cmd)
smart_log_cmd = f"{self.nvme_bin} smart-log {self.ctrl} " + \
f"--namespace-id={str(nsid)}"
proc = subprocess.Popen(smart_log_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
err = proc.wait()
self.assertEqual(err, 0, "ERROR : nvme smart log failed")
smart_log_output = proc.communicate()[0]
print(f"{smart_log_output}")
return err
def get_id_ctrl(self, vendor=False):
@ -480,10 +462,10 @@ class TestNVMe(unittest.TestCase):
- 0 on success, error code on failure.
"""
if not vendor:
id_ctrl_cmd = "nvme id-ctrl " + self.ctrl
id_ctrl_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl}"
else:
id_ctrl_cmd = "nvme id-ctrl --vendor-specific " + self.ctrl
print(id_ctrl_cmd)
id_ctrl_cmd = f"{self.nvme_bin} id-ctrl " +\
f"--vendor-specific {self.ctrl}"
proc = subprocess.Popen(id_ctrl_cmd,
shell=True,
stdout=subprocess.PIPE,
@ -500,13 +482,14 @@ class TestNVMe(unittest.TestCase):
- 0 on success, error code on failure.
"""
pattern = re.compile(r"^ Entry\[[ ]*[0-9]+\]")
error_log_cmd = "nvme error-log " + self.ctrl
error_log_cmd = f"{self.nvme_bin} error-log {self.ctrl}"
proc = subprocess.Popen(error_log_cmd,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
err = proc.wait()
self.assertEqual(err, 0, "ERROR : nvme error log failed")
# This sanity checkes the 'normal' output
line = proc.stdout.readline()
err_log_entry_count = int(line.split(" ")[5].strip().split(":")[1])
entry_count = 0
@ -523,42 +506,20 @@ class TestNVMe(unittest.TestCase):
- Returns:
- None
"""
block_size = mmap.PAGESIZE if int(lbads) < 9 else 2 ** int(lbads)
(ds, _) = self.get_lba_format_size()
block_size = ds if int(lbads) < 9 else 2 ** int(lbads)
ns_path = self.ctrl + "n" + str(nsid)
io_cmd = "dd if=" + ns_path + " of=/dev/null" + " bs=" + \
str(block_size) + " count=" + str(count) + " > /dev/null 2>&1"
print(io_cmd)
print(f"Running io: {io_cmd}")
run_io = subprocess.Popen(io_cmd, shell=True, stdout=subprocess.PIPE,
encoding='utf-8')
run_io_result = run_io.communicate()[1]
self.assertEqual(run_io_result, None)
io_cmd = "dd if=/dev/zero of=" + ns_path + " bs=" + \
str(block_size) + " count=" + str(count) + " > /dev/null 2>&1"
print(io_cmd)
print(f"Running io: {io_cmd}")
run_io = subprocess.Popen(io_cmd, shell=True, stdout=subprocess.PIPE,
encoding='utf-8')
run_io_result = run_io.communicate()[1]
self.assertEqual(run_io_result, None)
def supp_check_id_ctrl(self, key):
""" Wrapper for support check.
- Args:
- key : search key.
- Returns:
- value for key requested.
"""
id_ctrl = "nvme id-ctrl " + self.ctrl
print("\n" + id_ctrl)
proc = subprocess.Popen(id_ctrl,
shell=True,
stdout=subprocess.PIPE,
encoding='utf-8')
err = proc.wait()
self.assertEqual(err, 0, "ERROR : nvme Identify controller Data \
structure failed")
for line in proc.stdout:
if key in line:
key = line.replace(",", "", 1)
print(key)
val = (key.split(':'))[1].strip()
return int(val, 16)

View file

@ -43,7 +43,7 @@ class TestNVMeIO(TestNVMe):
""" Pre Section for TestNVMeIO """
super().setUp()
# common code used in various testcases.
self.data_size = 512
(self.data_size, _) = self.get_lba_format_size()
self.start_block = 0
self.block_count = 0
self.write_file = "write_file.txt"
@ -77,10 +77,10 @@ class TestNVMeIO(TestNVMe):
- Returns:
- return code for nvme write command.
"""
write_cmd = "nvme write " + self.ns1 + " --start-block=" + \
str(self.start_block) + " --block-count=" + \
str(self.block_count) + " --data-size=" + \
str(self.data_size) + " --data=" + self.write_file
write_cmd = f"{self.nvme_bin} write {self.ns1} " + \
f"--start-block={str(self.start_block)} " + \
f"--block-count={str(self.block_count)} " + \
f"--data-size={str(self.data_size)} --data={self.write_file}"
return self.exec_cmd(write_cmd)
def nvme_read(self):
@ -90,9 +90,8 @@ class TestNVMeIO(TestNVMe):
- Returns:
- return code for nvme read command.
"""
read_cmd = "nvme read " + self.ns1 + " --start-block=" + \
str(self.start_block) + " --block-count=" + \
str(self.block_count) + " --data-size=" + \
str(self.data_size) + " --data=" + self.read_file
print(read_cmd)
read_cmd = f"{self.nvme_bin} read {self.ns1} " + \
f"--start-block={str(self.start_block)} " + \
f"--block-count={str(self.block_count)} " + \
f"--data-size={str(self.data_size)} --data={self.read_file}"
return self.exec_cmd(read_cmd)

View file

@ -13,7 +13,7 @@ NVMe Verify Testcase:-
"""
from nvme_test import TestNVMe
from nvme_test import TestNVMe, to_decimal
class TestNVMeVerify(TestNVMe):
@ -25,9 +25,21 @@ class TestNVMeVerify(TestNVMe):
- test_log_dir : directory for logs, temp files.
"""
def verify_cmd_supported(self):
""" Wrapper for extracting optional NVM 'verify' command support
- Args:
- None
- Returns:
- True if 'verify' is supported, otherwise False
"""
return to_decimal(self.get_id_ctrl_field_value("oncs")) & (1 << 7)
def setUp(self):
""" Pre Section for TestNVMeVerify """
super().setUp()
if not self.verify_cmd_supported():
self.skipTest(
"because: Optional NVM Command 'Verify' (NVMVFYS) not supported")
self.start_block = 0
self.block_count = 0
self.namespace = 1
@ -44,10 +56,10 @@ class TestNVMeVerify(TestNVMe):
- Returns:
- return code for nvme verify command.
"""
verify_cmd = "nvme verify " + self.ctrl + \
" --namespace-id=" + str(self.namespace) + \
" --start-block=" + str(self.start_block) + \
" --block-count=" + str(self.block_count)
verify_cmd = f"{self.nvme_bin} verify {self.ctrl} " + \
f"--namespace-id={str(self.namespace)} " + \
f"--start-block={str(self.start_block)} " + \
f"--block-count={str(self.block_count)}"
return self.exec_cmd(verify_cmd)
def test_verify(self):

View file

@ -63,9 +63,9 @@ class TestNVMeUncor(TestNVMeIO):
- Returns:
- return code of nvme write uncorrectable command.
"""
write_uncor_cmd = "nvme write-uncor " + self.ns1 + \
" --start-block=" + str(self.start_block) + \
" --block-count=" + str(self.block_count)
write_uncor_cmd = f"{self.nvme_bin} write-uncor {self.ns1} " + \
f"--start-block={str(self.start_block)} " + \
f"--block-count={str(self.block_count)}"
return self.exec_cmd(write_uncor_cmd)
def test_write_uncor(self):

View file

@ -71,9 +71,9 @@ class TestNVMeWriteZeros(TestNVMeIO):
- Returns:
- return code for nvme write command.
"""
write_zeroes_cmd = "nvme write-zeroes " + self.ns1 + \
" --start-block=" + str(self.start_block) + \
" --block-count=" + str(self.block_count)
write_zeroes_cmd = f"{self.nvme_bin} write-zeroes {self.ns1} " + \
f"--start-block={str(self.start_block)} " + \
f"--block-count={str(self.block_count)}"
return self.exec_cmd(write_zeroes_cmd)
def validate_write_read(self):