Last active
October 9, 2015 00:21
-
-
Save ymmt2005/823d2b2e33eeba1ae07f to your computer and use it in GitHub Desktop.
Annotate "nvme id-ns -b" output tersely.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from __future__ import print_function | |
from argparse import ArgumentParser, RawDescriptionHelpFormatter | |
import re | |
import sys | |
# Constants | |
HELP_DESCRIPTION = '''\ | |
Annotate id-ns output for humans. | |
The output should be given via stdin like this: | |
sudo nvme id-ns /dev/nvme0 -n 1 -b | annotate-id-ns.py''' | |
RE_LINE = re.compile(r'^\[\s*(\d+)\]:0x([0-9a-fA-F]+)$') | |
RELATIVE_PERFORMANCE = { | |
0: 'Best', 1: 'Better', 2: 'Good', 3: 'Degraded', | |
} | |
# Functions | |
def parse_input(f): | |
'''Convert raw binary output from IDENTIFY NAMESPACE into binary string.''' | |
return ''.join(format(b, '08b') for b in reversed(bytearray(f.read()))) | |
def annotate(data): | |
'''Annotate list-ns output according to NVMe spec 1.2 Figure 92 & 93.''' | |
def decode(byte_offset, bit_offset, nbits): | |
pos = 1024 * 4 * 8 - byte_offset*8 - bit_offset - nbits | |
return int(data[pos:(pos+nbits)], base=2) | |
print('# of logical blocks:', decode(0, 0, 8*8)) | |
print('# of logical blocks after format:', decode(8, 0, 8*8)) | |
print('# of logical blocks in use:', decode(16, 0, 8*8)) | |
print('Support for deallocated or unwritten logical block error:', | |
decode(24, 2, 1) != 0) | |
print('Support for NAWUN/NAWUPF/NACWU:', | |
decode(24, 1, 1) != 0) | |
print('Support for thin provisioning:', | |
decode(24, 0, 1) != 0) | |
# the number of LBA formats is 0's based value. | |
nlbaf = decode(25, 0, 1*8)+1 | |
print('# of LBA formats:', nlbaf) | |
print('Metadata at the end of LBA:', | |
decode(26, 4, 1) != 0) | |
lbaf = decode(26, 0, 4) | |
print('LBA format ID (LBAF):', lbaf) | |
print('Metadata transfer using a separate buffer:', | |
decode(27, 1, 1) != 0) | |
print('Metadata transfer using extended data LBA:', | |
decode(27, 0, 1) != 0) | |
print('Support for PI transfer at the tail of metadata:', | |
decode(28, 4, 1) != 0) | |
print('Support for PI transfer at the head of metadata:', | |
decode(28, 3, 1) != 0) | |
print('Support for protection information Type 3:', | |
decode(28, 2, 1) != 0) | |
print('Support for protection information Type 2:', | |
decode(28, 1, 1) != 0) | |
print('Support for protection information Type 1:', | |
decode(28, 0, 1) != 0) | |
pi_type = decode(29, 0, 3) | |
if pi_type == 0: | |
print('Protection information is not enabled.') | |
else: | |
print('Protection information is enabled: Type', pi_type) | |
print('Protection information at the head of metadata:', | |
decode(29, 3, 1) != 0) | |
print('Shared namespace:', | |
'Yes' if decode(30, 0, 1) != 0 else 'No') | |
reservation = decode(31, 0, 8) | |
if reservation == 0: | |
print('Reservation is not supported.') | |
else: | |
print('Reservation support for Exclusive Access - All Registrants:', | |
decode(31, 6, 1) != 0) | |
print('Reservation support for Write Exclusive - All Registrants:', | |
decode(31, 5, 1) != 0) | |
print('Reservation support for Exclusive Access - Registrants Only:', | |
decode(31, 4, 1) != 0) | |
print('Reservation support for Write Exclusive - Registrants Only:', | |
decode(31, 3, 1) != 0) | |
print('Reservation support for Exclusive Access:', | |
decode(31, 2, 1) != 0) | |
print('Reservation support for Write Exclusive:', | |
decode(31, 1, 1) != 0) | |
print('Support for Persist Through Power Loss:', | |
decode(31, 0, 1) != 0) | |
print('Support for format progress indicator:', | |
decode(32, 7, 1) != 0) | |
print('% remains to be formatted:', decode(32, 0, 7)) | |
print('Namespace Atomic Write Unit Normal (NAWUN):', | |
decode(34, 0, 2*8)) | |
print('Namespace Atomic Write Unit Power Fail (NAWUPF):', | |
decode(36, 0, 2*8)) | |
print('Namespace Atomic Compare & Write Unit (NACWU):', | |
decode(38, 0, 2*8)) | |
print('Namespace Atomic Boundary Size Normal (NABSN):', | |
decode(40, 0, 2*8)) | |
print('Namespace Atomic Boundary Offset (NABO):', | |
decode(42, 0, 2*8)) | |
print('Namespace Atomic Boundary Size Power Fail (NABSPF):', | |
decode(44, 0, 2*8)) | |
print('NVM capacity in bytes:', decode(48, 0, 16*8)) | |
print('Namespace GUID:', format(decode(104, 0, 16*8), '032X')) | |
print('Namespace EUI64:', format(decode(120, 0, 8*8), '016X')) | |
for i, pos in enumerate(range(128, 192, 4)): | |
print_lbaf_info(i, decode(pos, 0, 4*8), lbaf) | |
def print_lbaf_info(n, data, in_use): | |
if data == 0: | |
return | |
if n == in_use: | |
print('LBAF{} (in use)'.format(n)) | |
else: | |
print('LBAF{}'.format(n)) | |
print(' Relative performance:', RELATIVE_PERFORMANCE[(data>>24)&3]) | |
print(' LBA data size:', 1<<((data>>16)&255)) | |
print(' Metadata size:', data&65535) | |
# Main | |
def main(): | |
p = ArgumentParser(description=HELP_DESCRIPTION, | |
formatter_class=RawDescriptionHelpFormatter) | |
p.parse_args() | |
f = sys.stdin | |
if hasattr(f, 'buffer'): | |
f = f.buffer | |
data = parse_input(f) | |
annotate(data) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment