Skip to content

Commit 4f5cb87

Browse files
authored
[Mellanox] Support read/write more than 1 page in a single platform API call (#18881)
- Why I did it Support read/write more than 1 page in a single platform API call. - How to verify it Manual and mock test Signed-off-by: Stephen Sun <[email protected]>
1 parent 7822c97 commit 4f5cb87

File tree

2 files changed

+80
-39
lines changed

2 files changed

+80
-39
lines changed

platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py

Lines changed: 62 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -355,25 +355,40 @@ def _read_eeprom(self, offset, num_bytes, log_on_error=True):
355355
Returns:
356356
bytearray: the content of EEPROM
357357
"""
358-
_, page, page_offset = self._get_page_and_page_offset(offset)
359-
if not page:
360-
return None
358+
result = None
359+
while num_bytes > 0:
360+
_, page, page_offset = self._get_page_and_page_offset(offset)
361+
if not page:
362+
return None
361363

362-
try:
363-
with open(page, mode='rb', buffering=0) as f:
364-
f.seek(page_offset)
365-
content = f.read(num_bytes)
366-
if ctypes.get_errno() != 0:
367-
raise IOError(f'errno = {os.strerror(ctypes.get_errno())}')
368-
logger.log_debug(f'read EEPROM sfp={self.sdk_index}, page={page}, page_offset={page_offset}, \
369-
size={num_bytes}, data={content}')
370-
except (OSError, IOError) as e:
371-
if log_on_error:
372-
logger.log_warning(f'Failed to read sfp={self.sdk_index} EEPROM page={page}, page_offset={page_offset}, \
373-
size={num_bytes}, offset={offset}, error = {e}')
374-
return None
364+
try:
365+
with open(page, mode='rb', buffering=0) as f:
366+
f.seek(page_offset)
367+
content = f.read(num_bytes)
368+
if not result:
369+
result = content
370+
else:
371+
result += content
372+
read_length = len(content)
373+
num_bytes -= read_length
374+
if num_bytes > 0:
375+
page_size = f.seek(0, os.SEEK_END)
376+
if page_offset + read_length == page_size:
377+
offset += read_length
378+
else:
379+
# Indicate read finished
380+
num_bytes = 0
381+
if ctypes.get_errno() != 0:
382+
raise IOError(f'errno = {os.strerror(ctypes.get_errno())}')
383+
logger.log_debug(f'read EEPROM sfp={self.sdk_index}, page={page}, page_offset={page_offset}, '\
384+
f'size={read_length}, data={content}')
385+
except (OSError, IOError) as e:
386+
if log_on_error:
387+
logger.log_warning(f'Failed to read sfp={self.sdk_index} EEPROM page={page}, page_offset={page_offset}, '\
388+
f'size={num_bytes}, offset={offset}, error = {e}')
389+
return None
375390

376-
return bytearray(content)
391+
return bytearray(result)
377392

378393
# write eeprom specfic bytes beginning from offset with size as num_bytes
379394
def write_eeprom(self, offset, num_bytes, write_buffer):
@@ -389,29 +404,37 @@ def write_eeprom(self, offset, num_bytes, write_buffer):
389404
logger.log_error("Error mismatch between buffer length and number of bytes to be written")
390405
return False
391406

392-
page_num, page, page_offset = self._get_page_and_page_offset(offset)
393-
if not page:
394-
return False
407+
while num_bytes > 0:
408+
page_num, page, page_offset = self._get_page_and_page_offset(offset)
409+
if not page:
410+
return False
395411

396-
try:
397-
if self._is_write_protected(page_num, page_offset, num_bytes):
398-
# write limited eeprom is not supported
399-
raise IOError('write limited bytes')
400-
401-
with open(page, mode='r+b', buffering=0) as f:
402-
f.seek(page_offset)
403-
ret = f.write(write_buffer[0:num_bytes])
404-
if ret != num_bytes:
405-
raise IOError(f'write return code = {ret}')
406-
if ctypes.get_errno() != 0:
407-
raise IOError(f'errno = {os.strerror(ctypes.get_errno())}')
408-
logger.log_debug(f'write EEPROM sfp={self.sdk_index}, page={page}, page_offset={page_offset}, \
409-
size={num_bytes}, data={write_buffer}')
410-
except (OSError, IOError) as e:
411-
data = ''.join('{:02x}'.format(x) for x in write_buffer)
412-
logger.log_error(f'Failed to write EEPROM data sfp={self.sdk_index} EEPROM page={page}, page_offset={page_offset}, size={num_bytes}, \
413-
offset={offset}, data = {data}, error = {e}')
414-
return False
412+
try:
413+
if self._is_write_protected(page_num, page_offset, num_bytes):
414+
# write limited eeprom is not supported
415+
raise IOError('write limited bytes')
416+
with open(page, mode='r+b', buffering=0) as f:
417+
f.seek(page_offset)
418+
ret = f.write(write_buffer[0:num_bytes])
419+
written_buffer = write_buffer[0:ret]
420+
if ret != num_bytes:
421+
page_size = f.seek(0, os.SEEK_END)
422+
if page_offset + ret == page_size:
423+
# Move to next page
424+
write_buffer = write_buffer[ret:num_bytes]
425+
offset += ret
426+
else:
427+
raise IOError(f'write return code = {ret}')
428+
num_bytes -= ret
429+
if ctypes.get_errno() != 0:
430+
raise IOError(f'errno = {os.strerror(ctypes.get_errno())}')
431+
logger.log_debug(f'write EEPROM sfp={self.sdk_index}, page={page}, page_offset={page_offset}, '\
432+
f'size={ret}, left={num_bytes}, data={written_buffer}')
433+
except (OSError, IOError) as e:
434+
data = ''.join('{:02x}'.format(x) for x in write_buffer)
435+
logger.log_error(f'Failed to write EEPROM data sfp={self.sdk_index} EEPROM page={page}, page_offset={page_offset}, size={num_bytes}, '\
436+
f'offset={offset}, data = {data}, error = {e}')
437+
return False
415438
return True
416439

417440
@classmethod

platform/mellanox/mlnx-platform-api/tests/test_sfp.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ def test_sfp_write_eeprom(self, mock_limited_eeprom, mock_get_page):
131131
handle.write.side_effect = OSError('')
132132
assert not sfp.write_eeprom(0, 1, bytearray([1]))
133133

134+
mo = mock.mock_open()
135+
print('after mock open')
136+
with mock.patch('sonic_platform.sfp.open', mo):
137+
handle = mo()
138+
handle.write.side_effect = [128, 128, 64]
139+
handle.seek.side_effect = [0, 128, 0, 128, 0]
140+
bytes_to_write = bytearray([0]*128 + [1]*128 + [2]*64)
141+
assert sfp.write_eeprom(0, 320, bytes_to_write)
142+
expected_calls = [mock.call(bytes_to_write), mock.call(bytes_to_write[128:]), mock.call(bytes_to_write[256:])]
143+
handle.write.assert_has_calls(expected_calls)
144+
134145
@mock.patch('sonic_platform.sfp.SFP._get_page_and_page_offset')
135146
def test_sfp_read_eeprom(self, mock_get_page):
136147
sfp = SFP(0)
@@ -152,6 +163,13 @@ def test_sfp_read_eeprom(self, mock_get_page):
152163
handle.read.side_effect = OSError('')
153164
assert sfp.read_eeprom(0, 1) is None
154165

166+
mo = mock.mock_open()
167+
with mock.patch('sonic_platform.sfp.open', mo):
168+
handle = mo()
169+
handle.read.side_effect = [b'\x00'*128, b'\x01'*128, b'\x02'*64]
170+
handle.seek.side_effect = [0, 128, 0, 128, 0]
171+
assert sfp.read_eeprom(0, 320) == bytearray([0]*128 + [1]*128 + [2]*64)
172+
155173
@mock.patch('sonic_platform.sfp.SFP._fetch_port_status')
156174
def test_is_port_admin_status_up(self, mock_port_status):
157175
mock_port_status.return_value = (0, True)

0 commit comments

Comments
 (0)