Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3e16dea

Browse files
committedJul 23, 2024
refactor(xcvrd): extract CMIS SM handling into a separate function
Signed-off-by: Wataru Ishida <wataru.ishid@gmail.com>
1 parent 8c89f6b commit 3e16dea

File tree

1 file changed

+323
-323
lines changed

1 file changed

+323
-323
lines changed
 

‎sonic-xcvrd/xcvrd/xcvrd.py

+323-323
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,328 @@ def wait_for_port_config_done(self, namespace):
13001300
if key in ["PortConfigDone", "PortInitDone"]:
13011301
break
13021302

1303+
def handle_cmis_state_machine(self, lport, info, is_fast_reboot):
1304+
state = get_cmis_state_from_state_db(lport, self.xcvr_table_helper.get_status_tbl(self.port_mapping.get_asic_id_for_logical_port(lport)))
1305+
if state in CMIS_TERMINAL_STATES or state == CMIS_STATE_UNKNOWN:
1306+
if state != CMIS_STATE_READY:
1307+
self.port_dict[lport]['appl'] = 0
1308+
self.port_dict[lport]['host_lanes_mask'] = 0
1309+
return
1310+
1311+
# Handle the case when Xcvrd was NOT running when 'host_tx_ready' or 'admin_status'
1312+
# was updated or this is the first run so reconcile the above two attributes
1313+
if 'host_tx_ready' not in self.port_dict[lport]:
1314+
self.port_dict[lport]['host_tx_ready'] = self.get_host_tx_status(lport)
1315+
1316+
if 'admin_status' not in self.port_dict[lport]:
1317+
self.port_dict[lport]['admin_status'] = self.get_port_admin_status(lport)
1318+
1319+
pport = int(info.get('index', "-1"))
1320+
speed = int(info.get('speed', "0"))
1321+
lanes = info.get('lanes', "").strip()
1322+
subport = info.get('subport', 0)
1323+
if pport < 0 or speed == 0 or len(lanes) < 1 or subport < 0:
1324+
return
1325+
1326+
# Desired port speed on the host side
1327+
host_speed = speed
1328+
host_lane_count = len(lanes.split(','))
1329+
1330+
# double-check the HW presence before moving forward
1331+
sfp = platform_chassis.get_sfp(pport)
1332+
if not sfp.get_presence():
1333+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_REMOVED)
1334+
return
1335+
1336+
try:
1337+
# Skip if XcvrApi is not supported
1338+
api = sfp.get_xcvr_api()
1339+
if api is None:
1340+
self.log_error("{}: skipping CMIS state machine since no xcvr api!!!".format(lport))
1341+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1342+
return
1343+
1344+
# Skip if it's not a paged memory device
1345+
if api.is_flat_memory():
1346+
self.log_notice("{}: skipping CMIS state machine for flat memory xcvr".format(lport))
1347+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1348+
return
1349+
1350+
# Skip if it's not a CMIS module
1351+
type = api.get_module_type_abbreviation()
1352+
if (type is None) or (type not in self.CMIS_MODULE_TYPES):
1353+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1354+
return
1355+
1356+
if api.is_coherent_module():
1357+
if 'tx_power' not in self.port_dict[lport]:
1358+
self.port_dict[lport]['tx_power'] = self.get_configured_tx_power_from_db(lport)
1359+
if 'laser_freq' not in self.port_dict[lport]:
1360+
self.port_dict[lport]['laser_freq'] = self.get_configured_laser_freq_from_db(lport)
1361+
except AttributeError:
1362+
# Skip if these essential routines are not available
1363+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1364+
return
1365+
except Exception as e:
1366+
self.log_error("{}: Exception in xcvr api: {}".format(lport, e))
1367+
log_exception_traceback()
1368+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1369+
return
1370+
1371+
# CMIS expiration and retries
1372+
#
1373+
# A retry should always start over at INSETRTED state, while the
1374+
# expiration will reset the state to INSETRTED and advance the
1375+
# retry counter
1376+
now = datetime.datetime.now()
1377+
expired = self.port_dict[lport].get('cmis_expired')
1378+
retries = self.port_dict[lport].get('cmis_retries', 0)
1379+
host_lanes_mask = self.port_dict[lport].get('host_lanes_mask', 0)
1380+
appl = self.port_dict[lport].get('appl', 0)
1381+
if state != CMIS_STATE_INSERTED and (host_lanes_mask <= 0 or appl < 1):
1382+
self.log_error("{}: Unexpected value for host_lanes_mask {} or appl {} in "
1383+
"{} state".format(lport, host_lanes_mask, appl, state))
1384+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1385+
return
1386+
1387+
self.log_notice("{}: {}G, lanemask=0x{:x}, state={}, appl {} host_lane_count {} "
1388+
"retries={}".format(lport, int(speed/1000), host_lanes_mask,
1389+
state, appl, host_lane_count, retries))
1390+
if retries > self.CMIS_MAX_RETRIES:
1391+
self.log_error("{}: FAILED".format(lport))
1392+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1393+
return
1394+
1395+
try:
1396+
# CMIS state transitions
1397+
if state == CMIS_STATE_INSERTED:
1398+
self.port_dict[lport]['appl'] = get_cmis_application_desired(api, host_lane_count, host_speed)
1399+
if self.port_dict[lport]['appl'] is None:
1400+
self.log_error("{}: no suitable app for the port appl {} host_lane_count {} "
1401+
"host_speed {}".format(lport, appl, host_lane_count, host_speed))
1402+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1403+
return
1404+
appl = self.port_dict[lport]['appl']
1405+
self.log_notice("{}: Setting appl={}".format(lport, appl))
1406+
1407+
self.port_dict[lport]['host_lanes_mask'] = self.get_cmis_host_lanes_mask(api,
1408+
appl, host_lane_count, subport)
1409+
if self.port_dict[lport]['host_lanes_mask'] <= 0:
1410+
self.log_error("{}: Invalid lane mask received - host_lane_count {} subport {} "
1411+
"appl {}!".format(lport, host_lane_count, subport, appl))
1412+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1413+
return
1414+
host_lanes_mask = self.port_dict[lport]['host_lanes_mask']
1415+
self.log_notice("{}: Setting host_lanemask=0x{:x}".format(lport, host_lanes_mask))
1416+
1417+
self.port_dict[lport]['media_lane_count'] = int(api.get_media_lane_count(appl))
1418+
self.port_dict[lport]['media_lane_assignment_options'] = int(api.get_media_lane_assignment_option(appl))
1419+
media_lane_count = self.port_dict[lport]['media_lane_count']
1420+
media_lane_assignment_options = self.port_dict[lport]['media_lane_assignment_options']
1421+
self.port_dict[lport]['media_lanes_mask'] = self.get_cmis_media_lanes_mask(api,
1422+
appl, lport, subport)
1423+
if self.port_dict[lport]['media_lanes_mask'] <= 0:
1424+
self.log_error("{}: Invalid media lane mask received - media_lane_count {} "
1425+
"media_lane_assignment_options {} subport {}"
1426+
" appl {}!".format(lport, media_lane_count, media_lane_assignment_options, subport, appl))
1427+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1428+
return
1429+
media_lanes_mask = self.port_dict[lport]['media_lanes_mask']
1430+
self.log_notice("{}: Setting media_lanemask=0x{:x}".format(lport, media_lanes_mask))
1431+
1432+
if self.port_dict[lport]['host_tx_ready'] != 'true' or \
1433+
self.port_dict[lport]['admin_status'] != 'up':
1434+
if is_fast_reboot and self.check_datapath_state(api, host_lanes_mask, ['DataPathActivated']):
1435+
self.log_notice("{} Skip datapath re-init in fast-reboot".format(lport))
1436+
else:
1437+
self.log_notice("{} Forcing Tx laser OFF".format(lport))
1438+
# Force DataPath re-init
1439+
api.tx_disable_channel(media_lanes_mask, True)
1440+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1441+
return
1442+
# Configure the target output power if ZR module
1443+
if api.is_coherent_module():
1444+
tx_power = self.port_dict[lport]['tx_power']
1445+
# Prevent configuring same tx power multiple times
1446+
if 0 != tx_power and tx_power != api.get_tx_config_power():
1447+
if 1 != self.configure_tx_output_power(api, lport, tx_power):
1448+
self.log_error("{} failed to configure Tx power = {}".format(lport, tx_power))
1449+
else:
1450+
self.log_notice("{} Successfully configured Tx power = {}".format(lport, tx_power))
1451+
1452+
# Set all the DP lanes AppSel to unused(0) when non default app code needs to be configured
1453+
if True == self.is_appl_reconfigure_required(api, appl):
1454+
self.log_notice("{}: Decommissioning all lanes/datapaths to default AppSel=0".format(lport))
1455+
if True != api.decommission_all_datapaths():
1456+
self.log_notice("{}: Failed to default to AppSel=0".format(lport))
1457+
self.force_cmis_reinit(lport, retries + 1)
1458+
return
1459+
1460+
need_update = self.is_cmis_application_update_required(api, appl, host_lanes_mask)
1461+
1462+
# For ZR module, Datapath needes to be re-initlialized on new channel selection
1463+
if api.is_coherent_module():
1464+
freq = self.port_dict[lport]['laser_freq']
1465+
# If user requested frequency is NOT the same as configured on the module
1466+
# force datapath re-initialization
1467+
if 0 != freq and freq != api.get_laser_config_freq():
1468+
if self.validate_frequency_and_grid(api, lport, freq) == True:
1469+
need_update = True
1470+
else:
1471+
# clear setting of invalid frequency config
1472+
self.port_dict[lport]['laser_freq'] = 0
1473+
1474+
if not need_update:
1475+
# No application updates
1476+
# As part of xcvrd restart, the TRANSCEIVER_INFO table is deleted and
1477+
# created with default value of 'N/A' for all the active apsel fields.
1478+
# The below (post_port_active_apsel_to_db) will ensure that the
1479+
# active apsel fields are updated correctly in the DB since
1480+
# the CMIS state remains unchanged during xcvrd restart
1481+
self.post_port_active_apsel_to_db(api, lport, host_lanes_mask)
1482+
self.log_notice("{}: no CMIS application update required...READY".format(lport))
1483+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1484+
return
1485+
self.log_notice("{}: force Datapath reinit".format(lport))
1486+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_DEINIT)
1487+
elif state == CMIS_STATE_DP_DEINIT:
1488+
# D.2.2 Software Deinitialization
1489+
api.set_datapath_deinit(host_lanes_mask)
1490+
1491+
# D.1.3 Software Configuration and Initialization
1492+
media_lanes_mask = self.port_dict[lport]['media_lanes_mask']
1493+
if not api.tx_disable_channel(media_lanes_mask, True):
1494+
self.log_notice("{}: unable to turn off tx power with host_lanes_mask {}".format(lport, host_lanes_mask))
1495+
self.port_dict[lport]['cmis_retries'] = retries + 1
1496+
return
1497+
1498+
#Sets module to high power mode and doesn't impact datapath if module is already in high power mode
1499+
api.set_lpmode(False)
1500+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_AP_CONF)
1501+
dpDeinitDuration = self.get_cmis_dp_deinit_duration_secs(api)
1502+
modulePwrUpDuration = self.get_cmis_module_power_up_duration_secs(api)
1503+
self.log_notice("{}: DpDeinit duration {} secs, modulePwrUp duration {} secs".format(lport, dpDeinitDuration, modulePwrUpDuration))
1504+
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds = max(modulePwrUpDuration, dpDeinitDuration))
1505+
1506+
elif state == CMIS_STATE_AP_CONF:
1507+
# Explicit control bit to apply custom Host SI settings.
1508+
# It will be set to 1 and applied via set_application if
1509+
# custom SI settings is applicable
1510+
ec = 0
1511+
1512+
# TODO: Use fine grained time when the CMIS memory map is available
1513+
if not self.check_module_state(api, ['ModuleReady']):
1514+
if (expired is not None) and (expired <= now):
1515+
self.log_notice("{}: timeout for 'ModuleReady'".format(lport))
1516+
self.force_cmis_reinit(lport, retries + 1)
1517+
return
1518+
1519+
if not self.check_datapath_state(api, host_lanes_mask, ['DataPathDeactivated']):
1520+
if (expired is not None) and (expired <= now):
1521+
self.log_notice("{}: timeout for 'DataPathDeactivated state'".format(lport))
1522+
self.force_cmis_reinit(lport, retries + 1)
1523+
return
1524+
1525+
if api.is_coherent_module():
1526+
# For ZR module, configure the laser frequency when Datapath is in Deactivated state
1527+
freq = self.port_dict[lport]['laser_freq']
1528+
if 0 != freq:
1529+
if 1 != self.configure_laser_frequency(api, lport, freq):
1530+
self.log_error("{} failed to configure laser frequency {} GHz".format(lport, freq))
1531+
else:
1532+
self.log_notice("{} configured laser frequency {} GHz".format(lport, freq))
1533+
1534+
# Stage custom SI settings
1535+
if optics_si_parser.optics_si_present():
1536+
optics_si_dict = {}
1537+
# Apply module SI settings if applicable
1538+
lane_speed = int(speed/1000)//host_lane_count
1539+
optics_si_dict = optics_si_parser.fetch_optics_si_setting(pport, lane_speed, sfp)
1540+
1541+
self.log_debug("Read SI parameters for port {} from optics_si_settings.json vendor file:".format(lport))
1542+
for key, sub_dict in optics_si_dict.items():
1543+
self.log_debug("{}".format(key))
1544+
for sub_key, value in sub_dict.items():
1545+
self.log_debug("{}: {}".format(sub_key, str(value)))
1546+
1547+
if optics_si_dict:
1548+
self.log_notice("{}: Apply Optics SI found for Vendor: {} PN: {} lane speed: {}G".
1549+
format(lport, api.get_manufacturer(), api.get_model(), lane_speed))
1550+
if not api.stage_custom_si_settings(host_lanes_mask, optics_si_dict):
1551+
self.log_notice("{}: unable to stage custom SI settings ".format(lport))
1552+
self.force_cmis_reinit(lport, retries + 1)
1553+
return
1554+
1555+
# Set Explicit control bit to apply Custom Host SI settings
1556+
ec = 1
1557+
1558+
# D.1.3 Software Configuration and Initialization
1559+
api.set_application(host_lanes_mask, appl, ec)
1560+
if not api.scs_apply_datapath_init(host_lanes_mask):
1561+
self.log_notice("{}: unable to set application and stage DP init".format(lport))
1562+
self.force_cmis_reinit(lport, retries + 1)
1563+
return
1564+
1565+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_INIT)
1566+
elif state == CMIS_STATE_DP_INIT:
1567+
if not self.check_config_error(api, host_lanes_mask, ['ConfigSuccess']):
1568+
if (expired is not None) and (expired <= now):
1569+
self.log_notice("{}: timeout for 'ConfigSuccess'".format(lport))
1570+
self.force_cmis_reinit(lport, retries + 1)
1571+
return
1572+
1573+
if hasattr(api, 'get_cmis_rev'):
1574+
# Check datapath init pending on module that supports CMIS 5.x
1575+
majorRev = int(api.get_cmis_rev().split('.')[0])
1576+
if majorRev >= 5 and not self.check_datapath_init_pending(api, host_lanes_mask):
1577+
self.log_notice("{}: datapath init not pending".format(lport))
1578+
self.force_cmis_reinit(lport, retries + 1)
1579+
return
1580+
1581+
# Ensure the Datapath is NOT Activated unless the host Tx siganl is good.
1582+
# NOTE: Some CMIS compliant modules may have 'auto-squelch' feature where
1583+
# the module won't take datapaths to Activated state if host tries to enable
1584+
# the datapaths while there is no good Tx signal from the host-side.
1585+
if self.port_dict[lport]['admin_status'] != 'up' or \
1586+
self.port_dict[lport]['host_tx_ready'] != 'true':
1587+
self.log_notice("{} waiting for host tx ready...".format(lport))
1588+
return
1589+
1590+
# D.1.3 Software Configuration and Initialization
1591+
api.set_datapath_init(host_lanes_mask)
1592+
dpInitDuration = self.get_cmis_dp_init_duration_secs(api)
1593+
self.log_notice("{}: DpInit duration {} secs".format(lport, dpInitDuration))
1594+
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=dpInitDuration)
1595+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_TXON)
1596+
elif state == CMIS_STATE_DP_TXON:
1597+
if not self.check_datapath_state(api, host_lanes_mask, ['DataPathInitialized']):
1598+
if (expired is not None) and (expired <= now):
1599+
self.log_notice("{}: timeout for 'DataPathInitialized'".format(lport))
1600+
self.force_cmis_reinit(lport, retries + 1)
1601+
return
1602+
1603+
# Turn ON the laser
1604+
media_lanes_mask = self.port_dict[lport]['media_lanes_mask']
1605+
api.tx_disable_channel(media_lanes_mask, False)
1606+
self.log_notice("{}: Turning ON tx power".format(lport))
1607+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_ACTIVATE)
1608+
elif state == CMIS_STATE_DP_ACTIVATE:
1609+
if not self.check_datapath_state(api, host_lanes_mask, ['DataPathActivated']):
1610+
if (expired is not None) and (expired <= now):
1611+
self.log_notice("{}: timeout for 'DataPathActivated'".format(lport))
1612+
self.force_cmis_reinit(lport, retries + 1)
1613+
return
1614+
1615+
self.log_notice("{}: READY".format(lport))
1616+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1617+
self.post_port_active_apsel_to_db(api, lport, host_lanes_mask)
1618+
1619+
except Exception as e:
1620+
self.log_error("{}: internal errors due to {}".format(lport, e))
1621+
log_exception_traceback()
1622+
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1623+
1624+
13031625
def task_worker(self):
13041626
self.xcvr_table_helper = XcvrTableHelper(self.namespaces)
13051627

@@ -1325,329 +1647,7 @@ def task_worker(self):
13251647
for lport, info in self.port_dict.items():
13261648
if self.task_stopping_event.is_set():
13271649
break
1328-
1329-
if lport not in self.port_dict:
1330-
continue
1331-
1332-
state = get_cmis_state_from_state_db(lport, self.xcvr_table_helper.get_status_tbl(self.port_mapping.get_asic_id_for_logical_port(lport)))
1333-
if state in CMIS_TERMINAL_STATES or state == CMIS_STATE_UNKNOWN:
1334-
if state != CMIS_STATE_READY:
1335-
self.port_dict[lport]['appl'] = 0
1336-
self.port_dict[lport]['host_lanes_mask'] = 0
1337-
continue
1338-
1339-
# Handle the case when Xcvrd was NOT running when 'host_tx_ready' or 'admin_status'
1340-
# was updated or this is the first run so reconcile the above two attributes
1341-
if 'host_tx_ready' not in self.port_dict[lport]:
1342-
self.port_dict[lport]['host_tx_ready'] = self.get_host_tx_status(lport)
1343-
1344-
if 'admin_status' not in self.port_dict[lport]:
1345-
self.port_dict[lport]['admin_status'] = self.get_port_admin_status(lport)
1346-
1347-
pport = int(info.get('index', "-1"))
1348-
speed = int(info.get('speed', "0"))
1349-
lanes = info.get('lanes', "").strip()
1350-
subport = info.get('subport', 0)
1351-
if pport < 0 or speed == 0 or len(lanes) < 1 or subport < 0:
1352-
continue
1353-
1354-
# Desired port speed on the host side
1355-
host_speed = speed
1356-
host_lane_count = len(lanes.split(','))
1357-
1358-
# double-check the HW presence before moving forward
1359-
sfp = platform_chassis.get_sfp(pport)
1360-
if not sfp.get_presence():
1361-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_REMOVED)
1362-
continue
1363-
1364-
try:
1365-
# Skip if XcvrApi is not supported
1366-
api = sfp.get_xcvr_api()
1367-
if api is None:
1368-
self.log_error("{}: skipping CMIS state machine since no xcvr api!!!".format(lport))
1369-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1370-
continue
1371-
1372-
# Skip if it's not a paged memory device
1373-
if api.is_flat_memory():
1374-
self.log_notice("{}: skipping CMIS state machine for flat memory xcvr".format(lport))
1375-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1376-
continue
1377-
1378-
# Skip if it's not a CMIS module
1379-
type = api.get_module_type_abbreviation()
1380-
if (type is None) or (type not in self.CMIS_MODULE_TYPES):
1381-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1382-
continue
1383-
1384-
if api.is_coherent_module():
1385-
if 'tx_power' not in self.port_dict[lport]:
1386-
self.port_dict[lport]['tx_power'] = self.get_configured_tx_power_from_db(lport)
1387-
if 'laser_freq' not in self.port_dict[lport]:
1388-
self.port_dict[lport]['laser_freq'] = self.get_configured_laser_freq_from_db(lport)
1389-
except AttributeError:
1390-
# Skip if these essential routines are not available
1391-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1392-
continue
1393-
except Exception as e:
1394-
self.log_error("{}: Exception in xcvr api: {}".format(lport, e))
1395-
log_exception_traceback()
1396-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1397-
continue
1398-
1399-
# CMIS expiration and retries
1400-
#
1401-
# A retry should always start over at INSETRTED state, while the
1402-
# expiration will reset the state to INSETRTED and advance the
1403-
# retry counter
1404-
now = datetime.datetime.now()
1405-
expired = self.port_dict[lport].get('cmis_expired')
1406-
retries = self.port_dict[lport].get('cmis_retries', 0)
1407-
host_lanes_mask = self.port_dict[lport].get('host_lanes_mask', 0)
1408-
appl = self.port_dict[lport].get('appl', 0)
1409-
if state != CMIS_STATE_INSERTED and (host_lanes_mask <= 0 or appl < 1):
1410-
self.log_error("{}: Unexpected value for host_lanes_mask {} or appl {} in "
1411-
"{} state".format(lport, host_lanes_mask, appl, state))
1412-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1413-
continue
1414-
1415-
self.log_notice("{}: {}G, lanemask=0x{:x}, state={}, appl {} host_lane_count {} "
1416-
"retries={}".format(lport, int(speed/1000), host_lanes_mask,
1417-
state, appl, host_lane_count, retries))
1418-
if retries > self.CMIS_MAX_RETRIES:
1419-
self.log_error("{}: FAILED".format(lport))
1420-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1421-
continue
1422-
1423-
try:
1424-
# CMIS state transitions
1425-
if state == CMIS_STATE_INSERTED:
1426-
self.port_dict[lport]['appl'] = get_cmis_application_desired(api, host_lane_count, host_speed)
1427-
if self.port_dict[lport]['appl'] is None:
1428-
self.log_error("{}: no suitable app for the port appl {} host_lane_count {} "
1429-
"host_speed {}".format(lport, appl, host_lane_count, host_speed))
1430-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1431-
continue
1432-
appl = self.port_dict[lport]['appl']
1433-
self.log_notice("{}: Setting appl={}".format(lport, appl))
1434-
1435-
self.port_dict[lport]['host_lanes_mask'] = self.get_cmis_host_lanes_mask(api,
1436-
appl, host_lane_count, subport)
1437-
if self.port_dict[lport]['host_lanes_mask'] <= 0:
1438-
self.log_error("{}: Invalid lane mask received - host_lane_count {} subport {} "
1439-
"appl {}!".format(lport, host_lane_count, subport, appl))
1440-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1441-
continue
1442-
host_lanes_mask = self.port_dict[lport]['host_lanes_mask']
1443-
self.log_notice("{}: Setting host_lanemask=0x{:x}".format(lport, host_lanes_mask))
1444-
1445-
self.port_dict[lport]['media_lane_count'] = int(api.get_media_lane_count(appl))
1446-
self.port_dict[lport]['media_lane_assignment_options'] = int(api.get_media_lane_assignment_option(appl))
1447-
media_lane_count = self.port_dict[lport]['media_lane_count']
1448-
media_lane_assignment_options = self.port_dict[lport]['media_lane_assignment_options']
1449-
self.port_dict[lport]['media_lanes_mask'] = self.get_cmis_media_lanes_mask(api,
1450-
appl, lport, subport)
1451-
if self.port_dict[lport]['media_lanes_mask'] <= 0:
1452-
self.log_error("{}: Invalid media lane mask received - media_lane_count {} "
1453-
"media_lane_assignment_options {} subport {}"
1454-
" appl {}!".format(lport, media_lane_count, media_lane_assignment_options, subport, appl))
1455-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1456-
continue
1457-
media_lanes_mask = self.port_dict[lport]['media_lanes_mask']
1458-
self.log_notice("{}: Setting media_lanemask=0x{:x}".format(lport, media_lanes_mask))
1459-
1460-
if self.port_dict[lport]['host_tx_ready'] != 'true' or \
1461-
self.port_dict[lport]['admin_status'] != 'up':
1462-
if is_fast_reboot and self.check_datapath_state(api, host_lanes_mask, ['DataPathActivated']):
1463-
self.log_notice("{} Skip datapath re-init in fast-reboot".format(lport))
1464-
else:
1465-
self.log_notice("{} Forcing Tx laser OFF".format(lport))
1466-
# Force DataPath re-init
1467-
api.tx_disable_channel(media_lanes_mask, True)
1468-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1469-
continue
1470-
# Configure the target output power if ZR module
1471-
if api.is_coherent_module():
1472-
tx_power = self.port_dict[lport]['tx_power']
1473-
# Prevent configuring same tx power multiple times
1474-
if 0 != tx_power and tx_power != api.get_tx_config_power():
1475-
if 1 != self.configure_tx_output_power(api, lport, tx_power):
1476-
self.log_error("{} failed to configure Tx power = {}".format(lport, tx_power))
1477-
else:
1478-
self.log_notice("{} Successfully configured Tx power = {}".format(lport, tx_power))
1479-
1480-
# Set all the DP lanes AppSel to unused(0) when non default app code needs to be configured
1481-
if True == self.is_appl_reconfigure_required(api, appl):
1482-
self.log_notice("{}: Decommissioning all lanes/datapaths to default AppSel=0".format(lport))
1483-
if True != api.decommission_all_datapaths():
1484-
self.log_notice("{}: Failed to default to AppSel=0".format(lport))
1485-
self.force_cmis_reinit(lport, retries + 1)
1486-
continue
1487-
1488-
need_update = self.is_cmis_application_update_required(api, appl, host_lanes_mask)
1489-
1490-
# For ZR module, Datapath needes to be re-initlialized on new channel selection
1491-
if api.is_coherent_module():
1492-
freq = self.port_dict[lport]['laser_freq']
1493-
# If user requested frequency is NOT the same as configured on the module
1494-
# force datapath re-initialization
1495-
if 0 != freq and freq != api.get_laser_config_freq():
1496-
if self.validate_frequency_and_grid(api, lport, freq) == True:
1497-
need_update = True
1498-
else:
1499-
# clear setting of invalid frequency config
1500-
self.port_dict[lport]['laser_freq'] = 0
1501-
1502-
if not need_update:
1503-
# No application updates
1504-
# As part of xcvrd restart, the TRANSCEIVER_INFO table is deleted and
1505-
# created with default value of 'N/A' for all the active apsel fields.
1506-
# The below (post_port_active_apsel_to_db) will ensure that the
1507-
# active apsel fields are updated correctly in the DB since
1508-
# the CMIS state remains unchanged during xcvrd restart
1509-
self.post_port_active_apsel_to_db(api, lport, host_lanes_mask)
1510-
self.log_notice("{}: no CMIS application update required...READY".format(lport))
1511-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1512-
continue
1513-
self.log_notice("{}: force Datapath reinit".format(lport))
1514-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_DEINIT)
1515-
elif state == CMIS_STATE_DP_DEINIT:
1516-
# D.2.2 Software Deinitialization
1517-
api.set_datapath_deinit(host_lanes_mask)
1518-
1519-
# D.1.3 Software Configuration and Initialization
1520-
media_lanes_mask = self.port_dict[lport]['media_lanes_mask']
1521-
if not api.tx_disable_channel(media_lanes_mask, True):
1522-
self.log_notice("{}: unable to turn off tx power with host_lanes_mask {}".format(lport, host_lanes_mask))
1523-
self.port_dict[lport]['cmis_retries'] = retries + 1
1524-
continue
1525-
1526-
#Sets module to high power mode and doesn't impact datapath if module is already in high power mode
1527-
api.set_lpmode(False)
1528-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_AP_CONF)
1529-
dpDeinitDuration = self.get_cmis_dp_deinit_duration_secs(api)
1530-
modulePwrUpDuration = self.get_cmis_module_power_up_duration_secs(api)
1531-
self.log_notice("{}: DpDeinit duration {} secs, modulePwrUp duration {} secs".format(lport, dpDeinitDuration, modulePwrUpDuration))
1532-
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds = max(modulePwrUpDuration, dpDeinitDuration))
1533-
1534-
elif state == CMIS_STATE_AP_CONF:
1535-
# Explicit control bit to apply custom Host SI settings.
1536-
# It will be set to 1 and applied via set_application if
1537-
# custom SI settings is applicable
1538-
ec = 0
1539-
1540-
# TODO: Use fine grained time when the CMIS memory map is available
1541-
if not self.check_module_state(api, ['ModuleReady']):
1542-
if (expired is not None) and (expired <= now):
1543-
self.log_notice("{}: timeout for 'ModuleReady'".format(lport))
1544-
self.force_cmis_reinit(lport, retries + 1)
1545-
continue
1546-
1547-
if not self.check_datapath_state(api, host_lanes_mask, ['DataPathDeactivated']):
1548-
if (expired is not None) and (expired <= now):
1549-
self.log_notice("{}: timeout for 'DataPathDeactivated state'".format(lport))
1550-
self.force_cmis_reinit(lport, retries + 1)
1551-
continue
1552-
1553-
if api.is_coherent_module():
1554-
# For ZR module, configure the laser frequency when Datapath is in Deactivated state
1555-
freq = self.port_dict[lport]['laser_freq']
1556-
if 0 != freq:
1557-
if 1 != self.configure_laser_frequency(api, lport, freq):
1558-
self.log_error("{} failed to configure laser frequency {} GHz".format(lport, freq))
1559-
else:
1560-
self.log_notice("{} configured laser frequency {} GHz".format(lport, freq))
1561-
1562-
# Stage custom SI settings
1563-
if optics_si_parser.optics_si_present():
1564-
optics_si_dict = {}
1565-
# Apply module SI settings if applicable
1566-
lane_speed = int(speed/1000)//host_lane_count
1567-
optics_si_dict = optics_si_parser.fetch_optics_si_setting(pport, lane_speed, sfp)
1568-
1569-
self.log_debug("Read SI parameters for port {} from optics_si_settings.json vendor file:".format(lport))
1570-
for key, sub_dict in optics_si_dict.items():
1571-
self.log_debug("{}".format(key))
1572-
for sub_key, value in sub_dict.items():
1573-
self.log_debug("{}: {}".format(sub_key, str(value)))
1574-
1575-
if optics_si_dict:
1576-
self.log_notice("{}: Apply Optics SI found for Vendor: {} PN: {} lane speed: {}G".
1577-
format(lport, api.get_manufacturer(), api.get_model(), lane_speed))
1578-
if not api.stage_custom_si_settings(host_lanes_mask, optics_si_dict):
1579-
self.log_notice("{}: unable to stage custom SI settings ".format(lport))
1580-
self.force_cmis_reinit(lport, retries + 1)
1581-
continue
1582-
1583-
# Set Explicit control bit to apply Custom Host SI settings
1584-
ec = 1
1585-
1586-
# D.1.3 Software Configuration and Initialization
1587-
api.set_application(host_lanes_mask, appl, ec)
1588-
if not api.scs_apply_datapath_init(host_lanes_mask):
1589-
self.log_notice("{}: unable to set application and stage DP init".format(lport))
1590-
self.force_cmis_reinit(lport, retries + 1)
1591-
continue
1592-
1593-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_INIT)
1594-
elif state == CMIS_STATE_DP_INIT:
1595-
if not self.check_config_error(api, host_lanes_mask, ['ConfigSuccess']):
1596-
if (expired is not None) and (expired <= now):
1597-
self.log_notice("{}: timeout for 'ConfigSuccess'".format(lport))
1598-
self.force_cmis_reinit(lport, retries + 1)
1599-
continue
1600-
1601-
if hasattr(api, 'get_cmis_rev'):
1602-
# Check datapath init pending on module that supports CMIS 5.x
1603-
majorRev = int(api.get_cmis_rev().split('.')[0])
1604-
if majorRev >= 5 and not self.check_datapath_init_pending(api, host_lanes_mask):
1605-
self.log_notice("{}: datapath init not pending".format(lport))
1606-
self.force_cmis_reinit(lport, retries + 1)
1607-
continue
1608-
1609-
# Ensure the Datapath is NOT Activated unless the host Tx siganl is good.
1610-
# NOTE: Some CMIS compliant modules may have 'auto-squelch' feature where
1611-
# the module won't take datapaths to Activated state if host tries to enable
1612-
# the datapaths while there is no good Tx signal from the host-side.
1613-
if self.port_dict[lport]['admin_status'] != 'up' or \
1614-
self.port_dict[lport]['host_tx_ready'] != 'true':
1615-
self.log_notice("{} waiting for host tx ready...".format(lport))
1616-
continue
1617-
1618-
# D.1.3 Software Configuration and Initialization
1619-
api.set_datapath_init(host_lanes_mask)
1620-
dpInitDuration = self.get_cmis_dp_init_duration_secs(api)
1621-
self.log_notice("{}: DpInit duration {} secs".format(lport, dpInitDuration))
1622-
self.port_dict[lport]['cmis_expired'] = now + datetime.timedelta(seconds=dpInitDuration)
1623-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_TXON)
1624-
elif state == CMIS_STATE_DP_TXON:
1625-
if not self.check_datapath_state(api, host_lanes_mask, ['DataPathInitialized']):
1626-
if (expired is not None) and (expired <= now):
1627-
self.log_notice("{}: timeout for 'DataPathInitialized'".format(lport))
1628-
self.force_cmis_reinit(lport, retries + 1)
1629-
continue
1630-
1631-
# Turn ON the laser
1632-
media_lanes_mask = self.port_dict[lport]['media_lanes_mask']
1633-
api.tx_disable_channel(media_lanes_mask, False)
1634-
self.log_notice("{}: Turning ON tx power".format(lport))
1635-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_DP_ACTIVATE)
1636-
elif state == CMIS_STATE_DP_ACTIVATE:
1637-
if not self.check_datapath_state(api, host_lanes_mask, ['DataPathActivated']):
1638-
if (expired is not None) and (expired <= now):
1639-
self.log_notice("{}: timeout for 'DataPathActivated'".format(lport))
1640-
self.force_cmis_reinit(lport, retries + 1)
1641-
continue
1642-
1643-
self.log_notice("{}: READY".format(lport))
1644-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY)
1645-
self.post_port_active_apsel_to_db(api, lport, host_lanes_mask)
1646-
1647-
except Exception as e:
1648-
self.log_error("{}: internal errors due to {}".format(lport, e))
1649-
log_exception_traceback()
1650-
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_FAILED)
1650+
self.handle_cmis_state_machine(lport, info, is_fast_reboot)
16511651

16521652
self.log_notice("Stopped")
16531653

0 commit comments

Comments
 (0)
Please sign in to comment.