Skip to content

Commit dffcc53

Browse files
mihirpat1yxieca
authored andcommitted
Add a subcommand to display a hexdump of transceiver EEPROM page (#2379)
* Add a subcommand to display a hexdump of transceiver EEPROM page What I did Added a subcommand to display the hexdump of transceiver EEPROM page specified by the user. "sfputil show eeprom-hexdump -p <port_name> -r <page_number>" has been added for this purpose and it requires both port name and page number as mandatory inputs. Lower page 0h is always displayed and the upper page is displayed based on the page number specified by the user How to verify it Verified the utility with 400G DD, 100G QSFP28 and 40G DAC Signed-off-by: Mihir Patel <[email protected]> * Added support for SFF-8472 EEPROM dump and addressed PR comments * Added more test cases Signed-off-by: Mihir Patel <[email protected]> * Changed -r option to -n and changed lower string for displaying A2h contents Signed-off-by: Mihir Patel <[email protected]> Signed-off-by: Mihir Patel <[email protected]>
1 parent 86175c2 commit dffcc53

File tree

2 files changed

+340
-0
lines changed

2 files changed

+340
-0
lines changed

sfputil/main.py

+147
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444

4545
MAX_LPL_FIRMWARE_BLOCK_SIZE = 116 #Bytes
4646

47+
PAGE_SIZE = 128
48+
PAGE_OFFSET = 128
49+
50+
SFF8472_A0_SIZE = 256
51+
4752
# TODO: We should share these maps and the formatting functions between sfputil and sfpshow
4853
QSFP_DATA_MAP = {
4954
'model': 'Vendor PN',
@@ -688,6 +693,148 @@ def eeprom(port, dump_dom, namespace):
688693

689694
click.echo(output)
690695

696+
# 'eeprom-hexdump' subcommand
697+
@show.command()
698+
@click.option('-p', '--port', metavar='<port_name>', required=True, help="Display SFP EEPROM hexdump for port <port_name>")
699+
@click.option('-n', '--page', metavar='<page_number>', help="Display SFP EEEPROM hexdump for <page_number_in_hex>")
700+
def eeprom_hexdump(port, page):
701+
"""Display EEPROM hexdump of SFP transceiver(s) for a given port name and page number"""
702+
output = ""
703+
704+
if platform_sfputil.is_logical_port(port) == 0:
705+
click.echo("Error: invalid port {}".format(port))
706+
print_all_valid_port_values()
707+
sys.exit(ERROR_INVALID_PORT)
708+
709+
if page is None:
710+
page = '0'
711+
712+
logical_port_name = port
713+
physical_port = logical_port_to_physical_port_index(logical_port_name)
714+
715+
if is_port_type_rj45(logical_port_name):
716+
click.echo("{}: SFP EEPROM Hexdump is not applicable for RJ45 port".format(port))
717+
sys.exit(ERROR_INVALID_PORT)
718+
719+
try:
720+
presence = platform_chassis.get_sfp(physical_port).get_presence()
721+
except NotImplementedError:
722+
click.echo("Sfp.get_presence() is currently not implemented for this platform")
723+
sys.exit(ERROR_NOT_IMPLEMENTED)
724+
725+
if not presence:
726+
click.echo("SFP EEPROM not detected")
727+
sys.exit(ERROR_NOT_IMPLEMENTED)
728+
else:
729+
try:
730+
id = platform_chassis.get_sfp(physical_port).read_eeprom(0, 1)
731+
if id is None:
732+
click.echo("Error: Failed to read EEPROM for offset 0!")
733+
sys.exit(ERROR_NOT_IMPLEMENTED)
734+
except NotImplementedError:
735+
click.echo("Sfp.read_eeprom() is currently not implemented for this platform")
736+
sys.exit(ERROR_NOT_IMPLEMENTED)
737+
738+
if id[0] == 0x3:
739+
output = eeprom_hexdump_sff8472(port, physical_port, page)
740+
else:
741+
output = eeprom_hexdump_sff8636(port, physical_port, page)
742+
743+
output += '\n'
744+
745+
click.echo(output)
746+
747+
def eeprom_hexdump_sff8472(port, physical_port, page):
748+
try:
749+
output = ""
750+
indent = ' ' * 8
751+
output += 'EEPROM hexdump for port {} page {}h'.format(port, page)
752+
output += '\n{}A0h dump'.format(indent)
753+
page_dump = platform_chassis.get_sfp(physical_port).read_eeprom(0, SFF8472_A0_SIZE)
754+
if page_dump is None:
755+
click.echo("Error: Failed to read EEPROM for A0h!")
756+
sys.exit(ERROR_NOT_IMPLEMENTED)
757+
758+
output += hexdump(indent, page_dump, 0)
759+
page_dump = platform_chassis.get_sfp(physical_port).read_eeprom(SFF8472_A0_SIZE, PAGE_SIZE)
760+
if page_dump is None:
761+
click.echo("Error: Failed to read EEPROM for A2h!")
762+
sys.exit(ERROR_NOT_IMPLEMENTED)
763+
else:
764+
output += '\n\n{}A2h dump (lower 128 bytes)'.format(indent)
765+
output += hexdump(indent, page_dump, 0)
766+
767+
page_dump = platform_chassis.get_sfp(physical_port).read_eeprom(SFF8472_A0_SIZE + PAGE_OFFSET + (int(page, base=16) * PAGE_SIZE), PAGE_SIZE)
768+
if page_dump is None:
769+
click.echo("Error: Failed to read EEPROM for A2h upper page!")
770+
sys.exit(ERROR_NOT_IMPLEMENTED)
771+
else:
772+
output += '\n\n{}A2h dump (upper 128 bytes) page {}h'.format(indent, page)
773+
output += hexdump(indent, page_dump, PAGE_OFFSET)
774+
except NotImplementedError:
775+
click.echo("Sfp.read_eeprom() is currently not implemented for this platform")
776+
sys.exit(ERROR_NOT_IMPLEMENTED)
777+
except ValueError:
778+
click.echo("Please enter a numeric page number")
779+
sys.exit(ERROR_NOT_IMPLEMENTED)
780+
781+
return output
782+
783+
def eeprom_hexdump_sff8636(port, physical_port, page):
784+
try:
785+
output = ""
786+
indent = ' ' * 8
787+
output += 'EEPROM hexdump for port {} page {}h'.format(port, page)
788+
output += '\n{}Lower page 0h'.format(indent)
789+
page_dump = platform_chassis.get_sfp(physical_port).read_eeprom(0, PAGE_SIZE)
790+
if page_dump is None:
791+
click.echo("Error: Failed to read EEPROM for page 0!")
792+
sys.exit(ERROR_NOT_IMPLEMENTED)
793+
794+
output += hexdump(indent, page_dump, 0)
795+
page_dump = platform_chassis.get_sfp(physical_port).read_eeprom(int(page, base=16) * PAGE_SIZE + PAGE_OFFSET, PAGE_SIZE)
796+
if page_dump is None:
797+
click.echo("Error: Failed to read EEPROM!")
798+
sys.exit(ERROR_NOT_IMPLEMENTED)
799+
else:
800+
output += '\n\n{}Upper page {}h'.format(indent, page)
801+
output += hexdump(indent, page_dump, PAGE_OFFSET)
802+
except NotImplementedError:
803+
click.echo("Sfp.read_eeprom() is currently not implemented for this platform")
804+
sys.exit(ERROR_NOT_IMPLEMENTED)
805+
except ValueError:
806+
click.echo("Please enter a numeric page number")
807+
sys.exit(ERROR_NOT_IMPLEMENTED)
808+
809+
return output
810+
811+
def convert_byte_to_valid_ascii_char(byte):
812+
if byte < 32 or 126 < byte:
813+
return '.'
814+
else:
815+
return chr(byte)
816+
817+
def hexdump(indent, data, mem_address):
818+
ascii_string = ''
819+
result = ''
820+
for byte in data:
821+
ascii_string = ascii_string + convert_byte_to_valid_ascii_char(byte)
822+
byte_string = "{:02x}".format(byte)
823+
if mem_address % 16 == 0:
824+
mem_address_string = "{:08x}".format(mem_address)
825+
result += '\n{}{} '.format(indent, mem_address_string)
826+
result += '{} '.format(byte_string)
827+
elif mem_address % 16 == 15:
828+
result += '{} '.format(byte_string)
829+
result += '|{}|'.format(ascii_string)
830+
ascii_string = ""
831+
elif mem_address % 16 == 7:
832+
result += ' {} '.format(byte_string)
833+
else:
834+
result += '{} '.format(byte_string)
835+
mem_address += 1
836+
837+
return result
691838

692839
# 'presence' subcommand
693840
@show.command()

0 commit comments

Comments
 (0)