@@ -86,6 +86,53 @@ def _check_ns_copy_limits(self):
8686 if missing :
8787 self .skipTest (f"{ ', ' .join (missing )} are 0, copy not supported on this namespace" )
8888
89+ def _get_current_ns_pif (self ):
90+ """
91+ Return the Protection Information Format (pif) of the currently active
92+ LBA format on self.ns1.
93+
94+ Reads the raw ``flbas`` byte from ``id-ns`` to determine the active
95+ lbaf index (NVMe spec: bits[3:0] are lbaf_index[3:0], bits[6:5] are
96+ lbaf_index[5:4]), then looks up that entry in the ``nvm-id-ns`` elbafs
97+ array. Returns 0 if either command fails or the pif field is absent
98+ (0 = 16-bit guard / no PI, the safe default for format 0/2 copy).
99+ """
100+ id_ns_cmd = f"{ self .nvme_bin } id-ns { self .ns1 } --output-format=json"
101+ result = self .run_cmd (id_ns_cmd )
102+ if result .returncode != 0 :
103+ return 0
104+ flbas = int (json .loads (result .stdout ).get ("flbas" , 0 ))
105+ lbaf_idx = (flbas & 0xF ) | (((flbas >> 5 ) & 0x3 ) << 4 )
106+
107+ nvm_id_ns_cmd = f"{ self .nvme_bin } nvm-id-ns { self .ns1 } --output-format=json"
108+ result = self .run_cmd (nvm_id_ns_cmd )
109+ if result .returncode != 0 :
110+ return 0
111+ elbafs = json .loads (result .stdout ).get ("elbafs" , [])
112+ if lbaf_idx < len (elbafs ):
113+ return elbafs [lbaf_idx ].get ("pif" , 0 )
114+ return 0
115+
116+ def _check_16b_guard_ns (self ):
117+ """
118+ Skip the test if the current namespace uses a non-16-bit-guard PI
119+ format and namespace management is not available to restore it.
120+
121+ Copy descriptor formats 0 and 2 require the namespace to use 16-bit
122+ guard PI (pif=0) or no PI. When namespace management is supported,
123+ TestNVMe.setUp() already recreates the namespace with flbas=0 (no
124+ metadata, no PI), so this is a no-op in that case. When namespace
125+ management is not available and the namespace is already in a 64-bit
126+ guard PI format (e.g. QEMU started with pif=2, or left over from a
127+ previous test run), the copy command would fail with "Invalid Format"
128+ rather than being skipped cleanly.
129+ """
130+ if not self .ns_mgmt_supported and self ._get_current_ns_pif () != 0 :
131+ self .skipTest (
132+ "current namespace uses non-16-bit-guard PI and namespace "
133+ "management is not supported; cannot run 16-bit guard copy test"
134+ )
135+
89136 def _find_64b_guard_lbaf_index (self ):
90137 """
91138 Search the nvm-id-ns elbafs for a format with 64-bit guard PI (pif == 2).
@@ -215,9 +262,16 @@ class TestNVMeCopyFormat0(TestNVMeCopy):
215262 NVMe Copy tests using Descriptor Format 0.
216263
217264 Format 0 uses 16-bit guard PI and copies within a single namespace.
218- No special namespace formatting is required.
265+ No special namespace formatting is required; the test is skipped if the
266+ current namespace is already using a non-16-bit-guard PI format and
267+ namespace management is not available to restore it.
219268 """
220269
270+ def setUp (self ):
271+ """ Pre Section for TestNVMeCopyFormat0 """
272+ super ().setUp ()
273+ self ._check_16b_guard_ns ()
274+
221275 def test_copy_format_0 (self ):
222276 """ Test copy with descriptor format 0 """
223277 self ._check_format_supported (0 )
@@ -275,13 +329,15 @@ def _run_format_3_copy(self, **kwargs):
275329 def test_copy_format_2 (self ):
276330 """ Test copy with descriptor format 2 """
277331 self ._check_format_supported (2 )
332+ self ._check_16b_guard_ns ()
278333 self ._check_ns_copy_limits ()
279334 self ._enable_cdfe_for_format (2 )
280335 self .copy (0 , 1 , 2 , descriptor_format = 2 , snsids = self .ns1_nsid )
281336
282337 def test_copy_format_2_sopts (self ):
283338 """ Test copy with descriptor format 2 and source options """
284339 self ._check_format_supported (2 )
340+ self ._check_16b_guard_ns ()
285341 self ._check_ns_copy_limits ()
286342 self ._enable_cdfe_for_format (2 )
287343 self .copy (0 , 1 , 2 , descriptor_format = 2 , snsids = self .ns1_nsid , sopts = 0 )
0 commit comments