@@ -1300,6 +1300,328 @@ def wait_for_port_config_done(self, namespace):
1300
1300
if key in ["PortConfigDone" , "PortInitDone" ]:
1301
1301
break
1302
1302
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
+
1303
1625
def task_worker (self ):
1304
1626
self .xcvr_table_helper = XcvrTableHelper (self .namespaces )
1305
1627
@@ -1325,329 +1647,7 @@ def task_worker(self):
1325
1647
for lport , info in self .port_dict .items ():
1326
1648
if self .task_stopping_event .is_set ():
1327
1649
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 )
1651
1651
1652
1652
self .log_notice ("Stopped" )
1653
1653
0 commit comments