Skip to content

Instantly share code, notes, and snippets.

@ymmt2005
Last active October 9, 2015 00:21
Show Gist options
  • Save ymmt2005/823d2b2e33eeba1ae07f to your computer and use it in GitHub Desktop.
Save ymmt2005/823d2b2e33eeba1ae07f to your computer and use it in GitHub Desktop.
Annotate "nvme id-ns -b" output tersely.
#!/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