[DellEMC]: EEPROM decoder for S6000, S6000-ON (#4718)
**- Why I did it** For decoding system EEPROM of S6000 based on Dell offset format and S6000-ON’s system EEPROM in ONIE TLV format. **- How I did it** - Differentiate between S6000 and S6000-ON using the product name available in ‘dmi’ ( “/sys/class/dmi/id/product_name” ) - For decoding S6000 system EEPROM in Dell offset format and updating the redis DB with the EEPROM contents, added a new class ‘EepromS6000’ in eeprom.py, - Renamed certain methods in both Eeprom, EepromS6000 classes to accommodate the plugin-specific methods. **- How to verify it** - Use 'decode-syseeprom' command to list the system EEPROM details. - Wrote a python script to load chassis class and call the appropriate methods. UT Logs: [S6000_eeprom_logs.txt](https://github.com/Azure/sonic-buildimage/files/4735515/S6000_eeprom_logs.txt), [S6000-ON_eeprom_logs.txt](https://github.com/Azure/sonic-buildimage/files/4735461/S6000-ON_eeprom_logs.txt) Test script: [eeprom_test_py.txt](https://github.com/Azure/sonic-buildimage/files/4735509/eeprom_test_py.txt)
This commit is contained in:
parent
9505bdb910
commit
54b284f4b0
@ -10,13 +10,21 @@
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_eeprom import eeprom_tlvinfo
|
||||
except ImportError, e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
from sonic_eeprom.eeprom_tlvinfo import TlvInfoDecoder
|
||||
from sonic_platform.eeprom import EepromS6000
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class board(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
class board(object):
|
||||
|
||||
def __init__(self, name, path, cpld_root, ro):
|
||||
self.eeprom_path = "/sys/class/i2c-adapter/i2c-10/10-0053/eeprom"
|
||||
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
||||
def __new__(cls, name, path, cpld_root, ro):
|
||||
eeprom_path = "/sys/class/i2c-adapter/i2c-10/10-0053/eeprom"
|
||||
|
||||
with open("/sys/class/dmi/id/product_name", "r") as fd:
|
||||
board_type = fd.read()
|
||||
|
||||
if 'S6000-ON' in board_type:
|
||||
return TlvInfoDecoder(eeprom_path, 0, '', True)
|
||||
else:
|
||||
return EepromS6000(is_plugin=True)
|
||||
|
@ -15,7 +15,7 @@ try:
|
||||
import subprocess
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from sonic_platform.sfp import Sfp
|
||||
from sonic_platform.eeprom import Eeprom
|
||||
from sonic_platform.eeprom import Eeprom, EepromS6000
|
||||
from sonic_platform.fan import Fan
|
||||
from sonic_platform.psu import Psu
|
||||
from sonic_platform.thermal import Thermal
|
||||
@ -68,7 +68,14 @@ class Chassis(ChassisBase):
|
||||
# Get Transceiver status
|
||||
self.modprs_register = self._get_transceiver_status()
|
||||
|
||||
self._eeprom = Eeprom()
|
||||
with open("/sys/class/dmi/id/product_name", "r") as fd:
|
||||
board_type = fd.read()
|
||||
|
||||
if 'S6000-ON' in board_type:
|
||||
self._eeprom = Eeprom()
|
||||
else:
|
||||
self._eeprom = EepromS6000()
|
||||
|
||||
for i in range(MAX_S6000_FAN):
|
||||
fan = Fan(i)
|
||||
self._fan_list.append(fan)
|
||||
@ -138,7 +145,7 @@ class Chassis(ChassisBase):
|
||||
Returns:
|
||||
string: The name of the chassis
|
||||
"""
|
||||
return self._eeprom.modelstr()
|
||||
return self._eeprom.get_model()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
@ -154,7 +161,7 @@ class Chassis(ChassisBase):
|
||||
Returns:
|
||||
string: Model/part number of chassis
|
||||
"""
|
||||
return self._eeprom.part_number_str()
|
||||
return self._eeprom.get_part_number()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
@ -162,7 +169,7 @@ class Chassis(ChassisBase):
|
||||
Returns:
|
||||
string: Serial number of chassis
|
||||
"""
|
||||
return self._eeprom.serial_str()
|
||||
return self._eeprom.get_serial()
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
@ -181,7 +188,7 @@ class Chassis(ChassisBase):
|
||||
A string containing the MAC address in the format
|
||||
'XX:XX:XX:XX:XX:XX'
|
||||
"""
|
||||
return self._eeprom.base_mac_addr()
|
||||
return self._eeprom.get_base_mac()
|
||||
|
||||
def get_serial_number(self):
|
||||
"""
|
||||
@ -191,7 +198,7 @@ class Chassis(ChassisBase):
|
||||
A string containing the hardware serial number for this
|
||||
chassis.
|
||||
"""
|
||||
return self._eeprom.serial_number_str()
|
||||
return self._eeprom.get_serial_number()
|
||||
|
||||
def get_system_eeprom_info(self):
|
||||
"""
|
||||
|
@ -17,12 +17,17 @@
|
||||
|
||||
|
||||
try:
|
||||
import binascii
|
||||
import os
|
||||
import redis
|
||||
import struct
|
||||
from collections import OrderedDict
|
||||
from sonic_platform_base.sonic_eeprom.eeprom_base import EepromDecoder
|
||||
from sonic_platform_base.sonic_eeprom.eeprom_tlvinfo import TlvInfoDecoder
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
STATE_DB_INDEX = 6
|
||||
|
||||
# PSU eeprom fields in format required by EepromDecoder
|
||||
psu_eeprom_format = [
|
||||
@ -200,13 +205,13 @@ class Eeprom(TlvInfoDecoder):
|
||||
|
||||
return (False, None)
|
||||
|
||||
def serial_number_str(self):
|
||||
def get_serial_number(self):
|
||||
"""
|
||||
Returns the serial number.
|
||||
"""
|
||||
return self.serial_number
|
||||
|
||||
def part_number_str(self):
|
||||
def get_part_number(self):
|
||||
"""
|
||||
Returns the part number.
|
||||
"""
|
||||
@ -222,19 +227,19 @@ class Eeprom(TlvInfoDecoder):
|
||||
return int(self.fan_type.encode('hex'), 16)
|
||||
|
||||
# System EEPROM specific methods
|
||||
def base_mac_addr(self):
|
||||
def get_base_mac(self):
|
||||
"""
|
||||
Returns the base MAC address found in the system EEPROM.
|
||||
"""
|
||||
return self.base_mac
|
||||
|
||||
def modelstr(self):
|
||||
def get_model(self):
|
||||
"""
|
||||
Returns the Model name.
|
||||
"""
|
||||
return self.model_str
|
||||
|
||||
def serial_str(self):
|
||||
def get_serial(self):
|
||||
"""
|
||||
Returns the servicetag number.
|
||||
"""
|
||||
@ -247,3 +252,252 @@ class Eeprom(TlvInfoDecoder):
|
||||
found in the system EEPROM.
|
||||
"""
|
||||
return self.eeprom_tlv_dict
|
||||
|
||||
|
||||
class EepromS6000(EepromDecoder):
|
||||
|
||||
_EEPROM_MAX_LEN = 128
|
||||
|
||||
_BLK_HDR_LEN = 6
|
||||
_BLK_HDR_MAGIC = '\x3a\x29'
|
||||
_BLK_HDR_REVID = 1
|
||||
|
||||
_BLK_CODE_MFG = 0x20
|
||||
_BLK_CODE_SW = 0x1F
|
||||
_BLK_CODE_MAC = 0x21
|
||||
|
||||
_BLK_MFG_FORMAT = [
|
||||
("PPID", 20), ("DPN Rev", 3), ("Service Tag", 7), ("Part Number", 10),
|
||||
("Part Number Rev", 3), ("Mfg Test Results", 2)
|
||||
]
|
||||
|
||||
_BLK_SW_FORMAT = [("Card ID", 4), ("Module ID", 2)]
|
||||
_BLK_MAC_FORMAT = [("Base MAC address", 6)]
|
||||
|
||||
_BLK_INFO = OrderedDict([
|
||||
(_BLK_CODE_MFG, {"name": "MFG BLOCK", "size": 64,
|
||||
"offset": 0x0, "format": _BLK_MFG_FORMAT}),
|
||||
(_BLK_CODE_SW, {"name": "SW BLOCK", "size": 48,
|
||||
"offset": 0x40, "format": _BLK_SW_FORMAT}),
|
||||
(_BLK_CODE_MAC, {"name": "MAC BLOCK", "size": 16,
|
||||
"offset": 0x70, "format": _BLK_MAC_FORMAT})
|
||||
])
|
||||
|
||||
def __init__(self, is_plugin=False):
|
||||
self.eeprom_path = "/sys/bus/i2c/devices/i2c-10/10-0053/eeprom"
|
||||
super(EepromS6000, self).__init__(self.eeprom_path, None, 0, '', True)
|
||||
|
||||
if not is_plugin:
|
||||
self.eeprom_data = self.read_eeprom()
|
||||
|
||||
def _is_valid_block_checksum(self, e):
|
||||
crc = self.compute_dell_crc(e[:-2])
|
||||
return crc == struct.unpack('<H', e[-2:])[0]
|
||||
|
||||
def _is_valid_block(self, e, blk_code):
|
||||
return (e[:2] == self._BLK_HDR_MAGIC
|
||||
and struct.unpack('<H', e[2:4])[0] == self._BLK_INFO[blk_code]["size"]
|
||||
and ord(e[4]) == blk_code
|
||||
and ord(e[5]) == self._BLK_HDR_REVID)
|
||||
|
||||
def _get_eeprom_field(self, e, blk_code, field_name):
|
||||
"""
|
||||
For a field name specified in the EEPROM format, returns the
|
||||
presence of the field and the value for the same.
|
||||
"""
|
||||
blk_start = self._BLK_INFO[blk_code]["offset"]
|
||||
blk_end = blk_start + self._BLK_INFO[blk_code]["size"]
|
||||
if not self._is_valid_block(e[blk_start:blk_end], blk_code):
|
||||
return (False, None)
|
||||
|
||||
field_start = blk_start + self._BLK_HDR_LEN
|
||||
for field in self._BLK_INFO[blk_code]["format"]:
|
||||
field_end = field_start + field[1]
|
||||
if field[0] == field_name:
|
||||
return (True, e[field_start:field_end])
|
||||
field_start = field_end
|
||||
|
||||
return (False, None)
|
||||
|
||||
def decode_eeprom(self, e):
|
||||
"""
|
||||
Decode and print out the contents of the EEPROM.
|
||||
"""
|
||||
print " Field Name Len Value"
|
||||
print "-------------------- --- --------------------"
|
||||
for blk_code in self._BLK_INFO.keys():
|
||||
blk_start = self._BLK_INFO[blk_code]["offset"]
|
||||
blk_end = blk_start + self._BLK_INFO[blk_code]["size"]
|
||||
if not self._is_valid_block(e[blk_start:blk_end], blk_code):
|
||||
print "Invalid Block starting at EEPROM offset %d" % (blk_start)
|
||||
return
|
||||
|
||||
offset = blk_start + self._BLK_HDR_LEN
|
||||
for f in self._BLK_INFO[blk_code]["format"]:
|
||||
if f[0] == "Num MACs" or f[0] == "Module ID":
|
||||
data = str(struct.unpack('<H', e[offset:offset+f[1]])[0])
|
||||
elif f[0] == "Card ID":
|
||||
data = hex(struct.unpack('<I', e[offset:offset+f[1]])[0])
|
||||
elif f[0] == "Base MAC address":
|
||||
data = ":".join([binascii.b2a_hex(T) for T in e[offset:offset+f[1]]]).upper()
|
||||
else:
|
||||
data = e[offset:offset+f[1]]
|
||||
print "{:<20s} {:>3d} {:<s}".format(f[0], f[1], data)
|
||||
offset += f[1]
|
||||
|
||||
if not self._is_valid_block_checksum(e[blk_start:blk_end]):
|
||||
print "(*** block checksum invalid)"
|
||||
|
||||
def read_eeprom(self):
|
||||
"""
|
||||
Read the EEPROM contents.
|
||||
"""
|
||||
return self.read_eeprom_bytes(self._EEPROM_MAX_LEN)
|
||||
|
||||
def read_eeprom_db(self):
|
||||
"""
|
||||
Print out the contents of the EEPROM from database.
|
||||
"""
|
||||
client = redis.Redis(db=STATE_DB_INDEX)
|
||||
db_state = client.hget('EEPROM_INFO|State', 'Initialized')
|
||||
if db_state != '1':
|
||||
return -1
|
||||
|
||||
print " Field Name Len Value"
|
||||
print "-------------------- --- --------------------"
|
||||
for blk_code in self._BLK_INFO.keys():
|
||||
blk_name = self._BLK_INFO[blk_code]["name"]
|
||||
blk_start = self._BLK_INFO[blk_code]["offset"]
|
||||
is_valid = client.hget('EEPROM_INFO|{}'.format(blk_name), 'Valid')
|
||||
if is_valid == '0':
|
||||
print "Invalid Block starting at EEPROM offset %d" % (blk_start)
|
||||
break
|
||||
|
||||
for f in self._BLK_INFO[blk_code]["format"]:
|
||||
data = client.hget('EEPROM_INFO|{}'.format(f[0]), 'Value')
|
||||
print "{:<20s} {:>3d} {:<s}".format(f[0], f[1], data)
|
||||
|
||||
is_checksum_valid = client.hget('EEPROM_INFO|{}'.format(blk_name), 'Checksum_Valid')
|
||||
if is_checksum_valid == '0':
|
||||
print "(*** block checksum invalid)"
|
||||
|
||||
return 0
|
||||
|
||||
def update_eeprom_db(self, e):
|
||||
"""
|
||||
Decode the contents of the EEPROM and update the contents to database
|
||||
"""
|
||||
client = redis.Redis(db=STATE_DB_INDEX)
|
||||
for blk_code in self._BLK_INFO.keys():
|
||||
blk_name = self._BLK_INFO[blk_code]["name"]
|
||||
blk_start = self._BLK_INFO[blk_code]["offset"]
|
||||
blk_end = blk_start + self._BLK_INFO[blk_code]["size"]
|
||||
if not self._is_valid_block(e[blk_start:blk_end], blk_code):
|
||||
client.hset('EEPROM_INFO|{}'.format(blk_name), 'Valid', '0')
|
||||
print "Invalid Block starting at EEPROM offset %d" % (blk_start)
|
||||
break
|
||||
else:
|
||||
client.hset('EEPROM_INFO|{}'.format(blk_name), 'Valid', '1')
|
||||
|
||||
offset = blk_start + self._BLK_HDR_LEN
|
||||
for f in self._BLK_INFO[blk_code]["format"]:
|
||||
if f[0] == "Num MACs" or f[0] == "Module ID":
|
||||
data = str(struct.unpack('<H', e[offset:offset+f[1]])[0])
|
||||
elif f[0] == "Card ID":
|
||||
data = hex(struct.unpack('<I', e[offset:offset+f[1]])[0])
|
||||
elif f[0] == "Base MAC address":
|
||||
data = ":".join([binascii.b2a_hex(T) for T in e[offset:offset+f[1]]]).upper()
|
||||
else:
|
||||
data = e[offset:offset+f[1]]
|
||||
client.hset('EEPROM_INFO|{}'.format(f[0]), 'Value', data)
|
||||
offset += f[1]
|
||||
|
||||
if not self._is_valid_block_checksum(e[blk_start:blk_end]):
|
||||
client.hset('EEPROM_INFO|{}'.format(blk_name), 'Checksum_Valid', '0')
|
||||
else:
|
||||
client.hset('EEPROM_INFO|{}'.format(blk_name), 'Checksum_Valid', '1')
|
||||
|
||||
client.hset('EEPROM_INFO|State', 'Initialized', '1')
|
||||
return 0
|
||||
|
||||
def get_base_mac(self):
|
||||
"""
|
||||
Returns the base MAC address found in the system EEPROM.
|
||||
"""
|
||||
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
||||
self._BLK_CODE_MAC, "Base MAC address")
|
||||
if valid:
|
||||
return ":".join([binascii.b2a_hex(T) for T in data]).upper()
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Returns the Model name.
|
||||
"""
|
||||
return 'S6000'
|
||||
|
||||
def get_part_number(self):
|
||||
"""
|
||||
Returns the part number.
|
||||
"""
|
||||
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
||||
self._BLK_CODE_MFG, "Part Number")
|
||||
if valid:
|
||||
return data
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Returns the Service tag.
|
||||
"""
|
||||
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
||||
self._BLK_CODE_MFG, "Service Tag")
|
||||
if valid:
|
||||
return data
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
def get_serial_number(self):
|
||||
"""
|
||||
Returns the serial number.
|
||||
"""
|
||||
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
||||
self._BLK_CODE_MFG, "PPID")
|
||||
if valid:
|
||||
return data
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
# EEPROM Plugin specific methods
|
||||
def is_checksum_valid(self, e):
|
||||
# Checksum is already calculated before
|
||||
return (True, 0)
|
||||
|
||||
def mgmtaddrstr(self, e):
|
||||
"""
|
||||
Returns the base MAC address.
|
||||
"""
|
||||
(valid, data) = self._get_eeprom_field(e, self._BLK_CODE_MAC, "Base MAC address")
|
||||
if valid:
|
||||
return ":".join([binascii.b2a_hex(T) for T in data]).upper()
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
def modelstr(self, e):
|
||||
"""
|
||||
Returns the Model name.
|
||||
"""
|
||||
return 'S6000'
|
||||
|
||||
def serial_number_str(self, e):
|
||||
"""
|
||||
Returns the Service Tag.
|
||||
"""
|
||||
(valid, data) = self._get_eeprom_field(e, self._BLK_CODE_MFG, "Service Tag")
|
||||
|
||||
if valid:
|
||||
return data
|
||||
else:
|
||||
return 'NA'
|
||||
|
@ -186,7 +186,7 @@ class Fan(FanBase):
|
||||
string: Part number of Fan
|
||||
"""
|
||||
if not self.is_psu_fan:
|
||||
return self.eeprom.part_number_str()
|
||||
return self.eeprom.get_part_number()
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
@ -199,7 +199,7 @@ class Fan(FanBase):
|
||||
"""
|
||||
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
|
||||
if not self.is_psu_fan:
|
||||
return self.eeprom.serial_number_str()
|
||||
return self.eeprom.get_serial_number()
|
||||
else:
|
||||
return 'NA'
|
||||
|
||||
|
@ -146,7 +146,7 @@ class Psu(PsuBase):
|
||||
Returns:
|
||||
string: Part number of PSU
|
||||
"""
|
||||
return self.eeprom.part_number_str()
|
||||
return self.eeprom.get_part_number()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
@ -156,7 +156,7 @@ class Psu(PsuBase):
|
||||
string: Serial number of PSU
|
||||
"""
|
||||
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
|
||||
return self.eeprom.serial_number_str()
|
||||
return self.eeprom.get_serial_number()
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user