openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

system_snake.c (70610B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * System Snake
      8  *
      9  * This file runs a system-level snake test.  Packets are injected into
     10  * a set of closed loops running around the system and left to cycle for
     11  * a period of time.  At a certain interval, the counters are checked to
     12  * confirm that traffic continues to flow.  At the end of the test, the
     13  * packets are drained and verified against the transmitted packets.
     14  * The final counter values are displayed on success.
     15  *
     16  * Port speed used is default (set in rc.soc) unless overridden on cmd
     17  * line.  Full duplex is used for snake test.  Loopback modes are MAC
     18  * and PHY.  EXT mode uses cables (crossover or straight) between ports
     19  * 1&2, 3&4, 5&6, etc.  Exposed HiGig ports are connected externally.
     20  *
     21  * Details:
     22  *
     23  * Initialization includes placing all of the ports into the proper
     24  * forwarding and/or loopback state.  VLANs are configured to include
     25  * all ports.  On 5690, the L2 table is programmed to forward the
     26  * packets to the next destination.  On 5670, the UC table is used.  The
     27  * packets are drained with filters.  All packet I/O takes place on one
     28  * 5690 for simplicity.
     29  *
     30  * The implementation borrows significantly from the test/lb_util.c
     31  * library of loopback utilities.  The packet I/O and verification
     32  * routines, port interconnection functions, and counter monitoring
     33  * procedures are the most important pieces of recycling.
     34  *
     35  * The default paths implemented here are 12 closed loops corresponding
     36  * to a 5690 port number.  That is, for a given path, a packet travels
     37  * from port n on the first 5690 to port n on each succeeding 5690 (via
     38  * the Higig uplinks to 5670).  From the final 5690 in the system, the
     39  * packet travel to the 5670 and loops externally out the back panel
     40  * ports.  Thus, the back panel ports must be connected in pairs by
     41  * cable.  After traveling these external loops, the packet is returned
     42  * to the first 5690 unit and continues the cycle.  The path is broken
     43  * at the end of the test by means of a filter on the first 5690.
     44  *
     45  * The first section of this file contains a number of defines which
     46  * might be tweaked to alter the parameters of the test.  Changing the
     47  * number of paths will require reworking the path interconnection
     48  * declarations.  Also, the test currently expects all ports to be
     49  * involved.  Omitting some paths or ports will produce a test failure.
     50  *
     51  * Exceeding bandwidth rates will result in dropped packets and test
     52  * failure.  For the 12 paths defined below, the 10 packets used in each
     53  * path were experimentally determined.  They result in traffic near
     54  * line rate on the 5670; they also do not exceed the CPU's ability to
     55  * drain packets before the system drops packets.
     56  */
     57 
     58 /*
     59  * This is the new implementation of the system snake test. It preserves
     60  * all the functionality of the original tests and uses the same
     61  * underlying functions to implement it.
     62  *
     63  * The new implementation goals were:
     64  *   1) to make it easy to add new platforms and snake configurations without 
     65  *      breaking the existing ones
     66  *   2) to overcome certain restrictions contained in the original code in
     67  *      order to allow for more complex system/snake configurations.
     68  *
     69  * The first goal is accomplished by replacing the complicated, platform-
     70  * dependent snake generation code with a simple generic function that
     71  * generates snakes according to specially constructed tables (which
     72  * are, indeed, platform-dependent). Now, adding a platform means adding
     73  * new snake definitions rather than changing the code, debugging it and
     74  * then testing that you haven't broken any other platforms.
     75  *
     76  * The new code also removes one of the major restrictions that the
     77  * original code. Specifically it allows various snake paths to co-exist
     78  * on the same platform. The code makes no assumption which chips is
     79  * used to inject packets into the snake or where to drain them from --
     80  * this information is implicitly encoded in the snake path
     81  * definition. The number of packets to be injected in the snake can
     82  * also be now specified on a per-snake basis allowing for snakes with
     83  * different speed/throughput to coexist.
     84  *
     85  * Adding a new platform:
     86  * ======================
     87  *
     88  * 1) Add a new member to the system names enum (SS_SYSID_XXX) right before 
     89  *    SS_SYSID_NUM element
     90  * 2) Add a platform name to the ss_sysid_str right before NULL. Make sure that
     91  *    the appropriate config variable is set on that box. For example, for
     92  *    the platform "foo" you should do "config add foo=1; config save"
     93  * 3) Specify the correct unit bitmap (it has '1's for all units present in 
     94  *    the box) in the ss_unit_bitmap array. For example, if your system has
     95  *    units 0, 1 and 2 the bitmap will be 0x7.
     96  * 4) Define the basic snake path(s) for the new platform.
     97  *    Specify the number of paths in the ss_num_paths array.
     98  *    Check that the number of snake "vertebrae" (the number of elements in
     99  *    the conn array) does not exceed SS_MAX_SNAKE_CONN.
    100  *    If it does, please update the constant.
    101  * 5) Create a snake list for the new platform. This list contains at least 1
    102  *    snake path, but is most handy when several snakes that differ only by
    103  *    port numbers should be created
    104  *    Check if the number of snakes for your platform exceeds SS_MAX_SNAKE. If 
    105  *    does, please
    106  *          6.1) Update the constant accordingly
    107  *          6.2) Add additional MAC addresses to ss_mac_src and ss_mac_dst 
    108  *               arrays.
    109  * 6) Add the platform-specific snake list to the ss_snake_table array
    110  *
    111  * Defining a snake
    112  * ================
    113  *
    114  * A snake describes a (looped) path that test packet(s) will take
    115  * through the the system. This path is system dependent and is designed
    116  * for each of the supported systems separately.
    117  *
    118  * A snake has a number of "vertebrae" or, more formally, a list of
    119  * connections.  Each connection (see system_snake_conn_t type
    120  * definition) defines where the packets that have been received on a
    121  * specific unit on a specific port with a specific module ID should go
    122  * and described by the following tuple:
    123  *     -- unit             The unit number on which that specific connection 
    124  *                         should be configured
    125  *     -- src_mod          The module ID of the arriving packet
    126  *     -- src_port         On which port the packet arrives
    127  *     -- dst_mod          What will be the new (rewritten) module ID
    128  *     -- dst_port         Through which port the packet should get out of the
    129  *                         chip (unit)
    130  *     -- flags            Which of {src,dst}_{mod,port} should be modified
    131  *                         (and how) based on the snake_port number on the 
    132  *                         snake list.
    133  *
    134  * Full snake definition includes:
    135  *    (a) the number of vertebrae,
    136  *    (b) the packet length increment that is applied as successive packets
    137  *        are transmitted,
    138  *    (c) the "return unit" which is the unit where the filter is set up
    139  *        to retrieve the packets at the end of the test, and 
    140  *    (d) list of connections (see system_snake_path_t definition).
    141  *
    142  * The number of packets to be injected into/drained from the snake is
    143  * definied rather implicitly by using packet_length_inc parameters, which
    144  * specifies how the test packet lengths should be computed: from
    145  * SS_PACKET_LENGTH_MIN to SS_PACKET_LENGTH_MAX with packet_length_inc
    146  * length increments.  Note that the packet length increment may be
    147  * specified on the command line which will override the hardcoded settings.
    148  *
    149  * The first connection in the snake definition is also used to
    150  * implicitly specify the unit that will be used to inject packets into
    151  * the snake and drain them from it at the end of the test, although (as
    152  * noted) the unit on which the filter is set up may differ for external
    153  * loopbacks.
    154  * 
    155  * Here is a definition of a snake for a Lancelot board with the
    156  * explanations:
    157  *
    158  * Line
    159  *   1  STATIC system_snake_path_t lancelot_snake_cw  = {
    160  *   2      8, 
    161  *   3      153,
    162  *   4      {
    163  *   5         {  1,  0,  0, 10,  0, SS_SP_PATH | SS_DP_PATH | SS_DM_PATH },
    164  *   6         {  0, 10,  7, 10,  6, SS_SM_PATH | SS_DM_PATH },
    165  *   7         {  0, 10,  5, 10,  4, SS_SM_PATH | SS_DM_PATH },
    166  *   8         {  0, 10,  3, 10,  2, SS_SM_PATH | SS_DM_PATH },
    167  *   9         {  4, 10, 12,  3,  0, SS_SM_PATH | SS_DP_PATH },
    168  *  10         {  4,  3,  0,  2,  0, SS_SP_PATH | SS_DP_PATH },
    169  *  11         {  3,  2,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    170  *  12         {  2,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    171  *  13      }
    172  *  14  };
    173  * 
    174  * Line  1: Define a static initialized structure
    175  * Line  2: The snake has 8 connections (vertebrae)
    176  * Line  3: The packet length increment for the packets injected into the snake
    177  *          is 153, which will result in packet lengths SS_PACKET_LENGTH_MIN 
    178  *          (68 bytes), SS_PACKET_LENGTH_MIN+153 (221 bytes), etc.
    179  * Line  5: The snake originates on the chip 1 (the leftmost 5690). If a packet
    180  *          arrives on port 0 and has a module ID 0 (and belongs to the VLAN
    181  *          SS_VLAN_BASE + 0), then it is sent to the module with the modid 10
    182  *          port 0. This results in the packet being forwarded to the switch
    183  *          fabric via the HiGig interface. Flags indicate the for the packets
    184  *          starting from port N rather than 0, N should be added to the source
    185  *          port, destination port and destination module number. In addition, 
    186  *          in case an external loopback mode is chosen, the destination port's
    187  *          LSB will be toggled. (see ss_port_interconnect_define()) 
    188  * Line  6: On unit 0 (5670 switch fabric) a packet arriving on port 7 (a HiGig
    189  *          connected to the leftmost 5690) with modid 10 should be forwarded
    190  *          to port 6 (one of the stacking HiGigs connected via an external 
    191  *          loopbak cable to another external HiGig port (5))
    192  * Line  7: On unit 0 (5670 switch fabric) a packet arriving on port 5
    193  *          (an external  HiGig port connected via loopback to port 6)
    194  *          with modid 10 should be forwarded to port 4 (another stacking HiGig
    195  *          port connected via an external loopbak cable to external HiGig 
    196  *          port (3))
    197  * Line  8: On unit 0 (5670 switch fabric) a packet arriving on port 3
    198  *          (an external  HiGig port connected via loopback to port 4)
    199  *          with modid 10 should be forwarded to port 2 (a HiGig port
    200  *          connected to the unit 4 (modid 3) which is te rightmost 5690)
    201  * Line  9: On unit 4 (the right-most 5690), packets arriving via the HiGig
    202  *          port (12) with modid 10 should be forwarded to modid (3) port 0 
    203  *          (basically port 0 on the same chip which is looped back to itself
    204  *          in MAC or PHY mode or port1 in the EXTERNAL mode).
    205  * Line 10: On unit 4 (the right-most 5690), packets arriving on port 0 with 
    206  *          modid 3 should be forwarded to port 0 on modid 2. 
    207  * Line 11: On unit 3 (the second from the right 5690), packets arriving on 
    208  *          port 0 with modid 2 should be forwarded to port 0 on modid 1. 
    209  * Line 10: On unit 2 (the third from the right 5690), packets arriving on 
    210  *          port 0 with modid 1 should be forwarded to port 0 on modid 0, which
    211  *          is the leftmost 5690 (unit 1) and this closes the snake.
    212  *
    213  ******************************************************************************
    214  *  System Snake for Firebolt 48 port POE board
    215  ******************************************************************************
    216  *  Platform info:
    217  *
    218  *  Firebolt 48 POE has two Firebolt (BCM56504) devices. These 2 devices
    219  *  are connected to each other through highGig Port 2 and 3. Highgig Port
    220  *  0 and 1 come out of the board and 48 Gigabit ethernet ports come to the
    221  *  front panel. Ports highGig 0 and 1 are configured in 10 Gig Ethernet mode
    222  *  for system snake test.
    223  *
    224  *  System snake can be run as both internal mode and external mode.
    225  *
    226  *  In internal mode, there are 28 snakes:
    227  *  
    228  *  24 snakes each of which connect from port X of Firebolt device 0 to
    229  *  port X of firebolt device 1. ports 0-11 use highGig port 2 and 
    230  *  port 12-23 use highGig port 3.
    231  *  
    232  *  2 snakes on device 0, one on XGE Port 0 and other on XGE port 1.
    233  *  2 snakes on device 1, one on XGE Port 0 and other on XGE port 1.
    234  *
    235  *  In external mode, there are 28 snakes:
    236  *
    237  *  12 snakes each of which goes from port X on device 0 to Port X+1. Packets
    238  *  are looped on device 1 from Port X+1 to Port X through external loopback 
    239  *  cables to Port X+1 of device 0. These snakes apply for even port numbers
    240  *  for instance port 0, 2 ..
    241  *  For external loopback, each odd numbered port should be connected through 
    242  *  loopback cable to port x+1 i.e. port 1 to port 2, port 3 to port 4 and so
    243  *  on.
    244  *  
    245  *
    246  *  12 snakes each of which goes from port X+1 on device 0 to Port X1. Packets
    247  *  are looped on device 1 from Port X to Port X+1 through external loopback 
    248  *  cables to Port X of device 0. These snakes are applicable for odd numbered
    249  *  ports, eg port 1,3..
    250  *
    251  *  2 snakes on device 0 between XGE Port 0 and 1 and vice versa, i.e.
    252  *    one between XGE0 to XGE1 and another between XGE1 to XGE0.
    253  *  2 snakes on device 1 between XGE Port 0 and 1 and vice versa, i.e.
    254  *    one between XGE0 to XGE1 and another between XGE1 to XGE0.
    255  */
    256 
    257 #ifdef INCLUDE_TEST
    258 
    259 #include <sal/appl/sal.h>
    260 #include <sal/appl/config.h>
    261 #include <shared/bsl.h>
    262 #include <soc/drv.h>
    263 
    264 #include <bcm/error.h>
    265 #include <bcm/tx.h>
    266 #include <bcm/link.h>
    267 #include <bcm/vlan.h>
    268 #include <bcm/stat.h>
    269 
    270 #include <appl/diag/system.h>
    271 #include <appl/diag/test.h>
    272 #include <appl/diag/dport.h>
    273 
    274 #include <appl/test/loopback2.h>
    275 
    276 #define SS_SOC_SCRIPT       "syssnake.soc"
    277  
    278 /* defines */
    279 #define SS_MAX_SNAKE                  28 /* max number of test snakes */
    280 #define SS_MAX_SNAKE_CONN             12 /* maximum snake length      */
    281 
    282 #define SS_PACKET_LENGTH_MIN          68
    283 #define SS_PACKET_LENGTH_MAX          1516
    284 #define SS_VLAN_BASE                  100
    285 #define SS_COS                        0
    286 #define SS_SEQUENCE_BASE              1
    287 #define SS_PATTERN_BASE               0x11223344
    288 #define SS_PATTERN_INC                0x01020304
    289 
    290 /* Default settings (can be overridden on cmd line) */
    291 #define SS_DURATION                   10
    292 #define SS_INTERVAL                   5
    293 #define SS_INTERPATH_WAIT             100000
    294 
    295 #define SS_UNIT_ITER(sysid, unit)                               \
    296         for ((unit) = 0; (unit) < SOC_MAX_NUM_DEVICES; (unit)++)                 \
    297             if (ss_unit_bitmap[(sysid)] & (1 << (unit)))
    298 
    299 #define SS_PACKETS_PER_PATH(path )                      \
    300         (((SS_PACKET_LENGTH_MAX - SS_PACKET_LENGTH_MIN) \
    301           / (path)->packet_length_inc) + 1)
    302 
    303 
    304 /* enums */
    305 enum {
    306     SS_SPEED_DEFAULT = 0,       /* ss_speed_str and ss_speed_mbits */
    307     SS_SPEED_MAX,               /* tables must match               */
    308     SS_SPEED_10,                
    309     SS_SPEED_100,
    310     SS_SPEED_1000,
    311     SS_SPEED_2500,
    312     SS_SPEED_3000,
    313     SS_SPEED_10G,
    314     SS_SPEED_NUM
    315 };
    316 
    317 enum {
    318     SS_MODE_MAC = 0,            /* ss_mode_str table must match */
    319     SS_MODE_PHY,
    320     SS_MODE_EXT,
    321     SS_MODE_NUM
    322 };
    323 
    324 /*
    325  * The system names enum
    326  */
    327 enum {
    328     SS_SYSID_FIREBOLT,
    329     SS_SYSID_FBPOE,
    330     SS_SYSID_LM_FB48,
    331     SS_SYSID_LM_FELIX48P,
    332     SS_SYSID_ICS_EB,
    333     SS_SYSID_GE_HU48,
    334     SS_SYSID_FE_HU48,
    335     SS_SYSID_NUM
    336 };
    337 
    338 /*
    339  * Flags for system snake definitions:
    340  *    SS_SP_PATH   -- add snake number to the base source port
    341  *    SS_SM_PATH   -- add snake number to the base source modid
    342  *    SS_DP_PATH   -- add snake number to the base destination port
    343  *                    and toggle the LSB in the resulting number in 
    344  *                    case we use external loopback
    345  *    SS_DM_PATH   -- add snake number to the base destination port
    346  *    SS_DP_NOEXT  -- do not toggle the last bit of the destination port number
    347  *                    in the external loopback mode. This is used to implement
    348  *                    external loopbacks on chips like 5673 that have only 1
    349  *                    Ethernet (XG) port. For these chips external loopbacks
    350  *                    are done by connecting Rx to Tx on the same chip.
    351  */
    352 enum {
    353     SS_SP_PATH =  0x00000001,
    354     SS_SM_PATH =  0x00000002,
    355     SS_DP_PATH =  0x00000004,
    356     SS_DM_PATH =  0x00000008,
    357     SS_DP_NOEXT = 0x00000010,
    358     SS_DP_FORCE = 0x00000020    /* Force toggling of DP LSB for all modes */
    359 };
    360 
    361 /* typedefs */
    362 typedef struct system_snake_opts_s {
    363     int                 sysid;          /* SS_SYSID_xxx */
    364     int                 got_herc;       /* Hercules chip present */   
    365     int                 speed;          /* SS_SPEED_xxx */
    366     int                 mode;           /* SS_MODE_xxx */
    367     int                 verbose;        /* Print a lot of status info. */
    368     int                 duration;       /* Overall test duration in sec. */
    369     int                 interval;       /* Interval to check counters */
    370     int                 pli;            /* Packet length increment */
    371 } system_snake_opts_t;
    372 
    373 typedef struct system_snake_info_s {
    374     lb2s_port_connect_t snake_pi[SS_MAX_SNAKE][SS_MAX_SNAKE_CONN];
    375     lb2s_port_connect_t cmic_return_pi[SS_MAX_SNAKE];
    376     int                 install_count[SOC_MAX_NUM_DEVICES];
    377     loopback2_test_t    lw[SOC_MAX_NUM_DEVICES];
    378     int                 num_packets[SOC_MAX_NUM_DEVICES];
    379     int                 io_unit[SOC_MAX_NUM_DEVICES];
    380     int                 io_unit_num;
    381     lb2_port_stat_t     *stats[SOC_MAX_NUM_DEVICES];
    382 } system_snake_info_t;
    383 
    384 typedef struct system_snake_conn_s {
    385     int          unit;
    386     int          src_mod;
    387     bcm_port_t   src_port;
    388     int          dst_mod;
    389     bcm_port_t   dst_port;
    390     unsigned int flags;
    391 } system_snake_conn_t;
    392 
    393 typedef struct system_snake_path_s {
    394     int        conn_count;
    395     int        packet_length_inc;
    396     int        return_unit; /* For ext, return unit may differ from tx unit */
    397     system_snake_conn_t conn[SS_MAX_SNAKE_CONN];
    398 } system_snake_path_t;
    399 
    400 typedef struct system_snake_list_s {
    401     int                  snake_port;
    402     system_snake_path_t *snake_path;
    403 } system_snake_list_t;
    404 
    405 /* locals */
    406 static const char *ss_speed_str[SS_SPEED_NUM + 1] = {
    407     "Default",          /* SS_SPEED_DEFAULT */
    408     "MAXimum",          /* SS_SPEED_MAX */
    409     "10fullduplex",     /* SS_SPEED_10 */
    410     "100fullduplex",    /* SS_SPEED_100 */
    411     "1000fullduplex",   /* SS_SPEED_1000 */
    412     "2500fullduplex",   /* SS_SPEED_2500 */
    413     "3000fullduplex",   /* SS_SPEED_3000 */
    414     "10Gfullduplex",    /* SS_SPEED_10G */
    415     NULL
    416 };
    417 
    418 static int ss_speed_mbits[SS_SPEED_NUM] = {
    419     0,                  /* Not used */  
    420     0,                  /* Not used */  
    421     10,                 /* 10Mbps */
    422     100,                /* 100Mbps */
    423     1000,               /* 1Gbps */
    424     2500,               /* 2.5 Gbps */
    425     3000,               /* 3.0 Gbps */
    426     10000               /* 10Gbps */
    427 };
    428 
    429 static int ss_speed_abil[SS_SPEED_NUM] = {
    430     0,                  /* Not used */  
    431     0,                  /* Not used */  
    432     BCM_PORT_ABIL_10MB_FD, 
    433     BCM_PORT_ABIL_100MB_FD, 
    434     BCM_PORT_ABIL_1000MB_FD, 
    435     BCM_PORT_ABIL_2500MB_FD,
    436     BCM_PORT_ABIL_3000MB_FD,
    437     BCM_PORT_ABIL_10GB_FD 
    438 };
    439 
    440 
    441 static const char *ss_mode_str[SS_MODE_NUM + 1] = {
    442     "MAC",              /* SS_MODE_MAC */
    443     "PHY",              /* SS_MODE_PHY */
    444     "EXT",              /* SS_MODE_EXT */
    445     NULL
    446 };
    447 
    448 static const char *ss_sysid_str[SS_SYSID_NUM + 1] = {
    449     "firebolt",         /* SS_SYSID_FIREBOLT  */
    450     "fbpoe",            /* SS_SYSID_FBPOE */
    451     "lmfb48",           /* SS_SYSID_LM_FB48 */
    452     "felix48",          /* SS_SYSID_LM_FELIX48P */
    453     "ics_eb",           /* SS_SYSID_ICS_EB */
    454     "ge_hu_48p",        /* SS_SYSID_GE_HU48 */
    455     "fe_hu_48p",        /* SS_SYSID_FE_HU48 */
    456     NULL
    457 };
    458 
    459 STATIC uint32 ss_unit_bitmap[SS_SYSID_NUM] = {
    460     0x01,       /* SS_SYSID_FIREBOLT */
    461     0x03,       /* SS_SYSID_FBPOE     */
    462     0x03,       /* SS_SYSID_LM_FB48   */
    463     0x03,       /* SS_SYSID_LM_FELIX48P */
    464     0x03,       /* SS_SYSID_ICS_EB */
    465     0x03,       /* SS_SYSID_GE_HU48 */
    466     0x03,       /* SS_SYSID_FE_HU48 */
    467 };
    468 
    469 STATIC uint32 ss_num_paths[SS_SYSID_NUM] = {
    470     28,         /* SS_SYSID_FIREBOLT */
    471     28,         /* SS_SYSID_FBPOE     */
    472     24,         /* SS_SYSID_LM_FB48   */
    473     27,         /* SS_SYSID_LM_FELIX48P */
    474     26,         /* SS_SYSID_ICS_EB */
    475     28,         /* SS_SYSID_GE_HU48 */
    476     26,         /* SS_SYSID_FE_HU48 */
    477 };
    478 
    479 STATIC char * ss_init_file[SS_SYSID_NUM] = {
    480     NULL,             /* SS_SYSID_FIREBOLT */
    481     SS_SOC_SCRIPT,    /* SS_SYSID_FBPOE     */
    482     SS_SOC_SCRIPT,    /* SS_SYSID_LM_FB48   */
    483     NULL,             /* SS_SYSID_LM_FELIX48P */
    484     SS_SOC_SCRIPT,    /* SS_SYSID_ICS_EB */
    485     SS_SOC_SCRIPT,    /* SS_SYSID_GE_HU48 */
    486     SS_SOC_SCRIPT,    /* SS_SYSID_FE_HU48 */
    487 };
    488 
    489 STATIC sal_mac_addr_t ss_mac_src[SS_MAX_SNAKE] = {
    490     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
    491     {0x00, 0x11, 0x22, 0x33, 0x44, 0x66},
    492     {0x00, 0x11, 0x22, 0x33, 0x44, 0x77},
    493     {0x00, 0x11, 0x22, 0x33, 0x44, 0x88},
    494     {0x00, 0x11, 0x22, 0x33, 0x44, 0x99},
    495     {0x00, 0x11, 0x22, 0x33, 0x44, 0xaa},
    496     {0x00, 0x11, 0x22, 0x33, 0x44, 0xbb},
    497     {0x00, 0x11, 0x22, 0x33, 0x44, 0xcc},
    498     {0x00, 0x11, 0x22, 0x33, 0x44, 0xdd},
    499     {0x00, 0x11, 0x22, 0x33, 0x44, 0xee},
    500     {0x00, 0x11, 0x22, 0x33, 0x44, 0xff},
    501     {0x00, 0x11, 0x22, 0x33, 0x44, 0x00},
    502     {0x00, 0x11, 0x22, 0x33, 0x44, 0x11},
    503     {0x00, 0x11, 0x22, 0x33, 0x44, 0x12},
    504     {0x00, 0x11, 0x22, 0x33, 0x45, 0x55},
    505     {0x00, 0x11, 0x22, 0x33, 0x45, 0x66},
    506     {0x00, 0x11, 0x22, 0x33, 0x45, 0x77},
    507     {0x00, 0x11, 0x22, 0x33, 0x45, 0x88},
    508     {0x00, 0x11, 0x22, 0x33, 0x45, 0x99},
    509     {0x00, 0x11, 0x22, 0x33, 0x45, 0xaa},
    510     {0x00, 0x11, 0x22, 0x33, 0x45, 0xbb},
    511     {0x00, 0x11, 0x22, 0x33, 0x45, 0xcc},
    512     {0x00, 0x11, 0x22, 0x33, 0x45, 0xdd},
    513     {0x00, 0x11, 0x22, 0x33, 0x45, 0xee},
    514     {0x00, 0x11, 0x22, 0x33, 0x45, 0xff},
    515     {0x00, 0x11, 0x22, 0x33, 0x45, 0x00},
    516     {0x00, 0x11, 0x22, 0x33, 0x45, 0x11},
    517     {0x00, 0x11, 0x22, 0x33, 0x45, 0x12},
    518 };
    519 
    520 STATIC sal_mac_addr_t ss_mac_dst[SS_MAX_SNAKE] = {
    521     {0x66, 0x77, 0x88, 0x99, 0xaa, 0xff},
    522     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x00},
    523     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x11},
    524     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x22},
    525     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x33},
    526     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x44},
    527     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x55},
    528     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x66},
    529     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x77},
    530     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x88},
    531     {0x66, 0x77, 0x88, 0x99, 0xaa, 0x99},
    532     {0x66, 0x77, 0x88, 0x99, 0xaa, 0xaa},
    533     {0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb},
    534     {0x66, 0x77, 0x88, 0x99, 0xaa, 0xcc},
    535     {0x66, 0x77, 0x88, 0x99, 0xab, 0xff},
    536     {0x66, 0x77, 0x88, 0x99, 0xab, 0x00},
    537     {0x66, 0x77, 0x88, 0x99, 0xab, 0x11},
    538     {0x66, 0x77, 0x88, 0x99, 0xab, 0x22},
    539     {0x66, 0x77, 0x88, 0x99, 0xab, 0x33},
    540     {0x66, 0x77, 0x88, 0x99, 0xab, 0x44},
    541     {0x66, 0x77, 0x88, 0x99, 0xab, 0x55},
    542     {0x66, 0x77, 0x88, 0x99, 0xab, 0x66},
    543     {0x66, 0x77, 0x88, 0x99, 0xab, 0x77},
    544     {0x66, 0x77, 0x88, 0x99, 0xab, 0x88},
    545     {0x66, 0x77, 0x88, 0x99, 0xab, 0x99},
    546     {0x66, 0x77, 0x88, 0x99, 0xab, 0xaa},
    547     {0x66, 0x77, 0x88, 0x99, 0xab, 0xbb},
    548     {0x66, 0x77, 0x88, 0x99, 0xab, 0xcc},
    549 };
    550 
    551 
    552 /*
    553  * Snake descriptions per board
    554  */
    555 
    556 /*
    557  * Firebolt uses 28 snakes, one per GE/XE port on 56504.  
    558  */
    559 
    560 STATIC system_snake_path_t firebolt_snake_cw = {
    561     1,
    562     480,
    563     0,
    564     { /*   u  sm  sp  dm  dp  flags */
    565         {  0,  0,    0, 0,   0, SS_DP_PATH | SS_DP_FORCE },
    566     }
    567 };
    568 
    569 STATIC system_snake_list_t firebolt_snake_test[] = {
    570     {   0, &firebolt_snake_cw },
    571     {   1, &firebolt_snake_cw },
    572     {   2, &firebolt_snake_cw },
    573     {   3, &firebolt_snake_cw },
    574     {   4, &firebolt_snake_cw },
    575     {   5, &firebolt_snake_cw },
    576     {   6, &firebolt_snake_cw },
    577     {   7, &firebolt_snake_cw },
    578     {   8, &firebolt_snake_cw },
    579     {   9, &firebolt_snake_cw },
    580     {  10, &firebolt_snake_cw },
    581     {  11, &firebolt_snake_cw },
    582     {  12, &firebolt_snake_cw },
    583     {  13, &firebolt_snake_cw },
    584     {  14, &firebolt_snake_cw },
    585     {  15, &firebolt_snake_cw },
    586     {  16, &firebolt_snake_cw },
    587     {  17, &firebolt_snake_cw },
    588     {  18, &firebolt_snake_cw },
    589     {  19, &firebolt_snake_cw },
    590     {  20, &firebolt_snake_cw },
    591     {  21, &firebolt_snake_cw },
    592     {  22, &firebolt_snake_cw },
    593     {  23, &firebolt_snake_cw },
    594     {  24, &firebolt_snake_cw },
    595     {  25, &firebolt_snake_cw },
    596     {  26, &firebolt_snake_cw },
    597     {  27, &firebolt_snake_cw },
    598 };
    599 
    600 /*
    601  * POE uses 2 snakes, one per GE port on 56504.
    602  * For even port numbers they go clockwise and for odd port 
    603  * numbers they go counter-clockwise. Also there are 4 snakes
    604  * one each XGE0-1 port on each device.
    605  */
    606 STATIC system_snake_path_t fbpoe_snake_cw  = {
    607     2, 
    608     183,
    609     0,
    610     { /*   u  sm  sp  dm  dp  flags */
    611         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    612         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    613     }
    614 };
    615 
    616 STATIC system_snake_path_t fbpoe_snake_ccw = {
    617     2,
    618     183,
    619     0,
    620     { /*   u  sm  sp  dm  dp  flags */
    621         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    622         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    623     }              
    624 };
    625 
    626 STATIC system_snake_path_t fbpoe_10ge_u0_snake_cw  = {
    627     1, 
    628     480,
    629     0,
    630     { /*   u  sm  sp  dm  dp  flags */
    631         {  0,  0,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    632     }
    633 };
    634 
    635 STATIC system_snake_path_t fbpoe_10ge_u1_snake_cw  = {
    636     1, 
    637     480,
    638     1,
    639     { /*   u  sm  sp  dm  dp  flags */
    640         {  1,  1,   0,  1,   0, SS_SP_PATH | SS_DP_PATH },
    641     }
    642 };
    643 
    644 STATIC system_snake_list_t fbpoe_snake_test[] = {
    645     {  0, &fbpoe_snake_cw },
    646     {  1, &fbpoe_snake_ccw },
    647     {  2, &fbpoe_snake_cw },
    648     {  3, &fbpoe_snake_ccw },
    649     {  4, &fbpoe_snake_cw },
    650     {  5, &fbpoe_snake_ccw },
    651     {  6, &fbpoe_snake_cw },
    652     {  7, &fbpoe_snake_ccw },
    653     {  8, &fbpoe_snake_cw },
    654     {  9, &fbpoe_snake_ccw },
    655     { 10, &fbpoe_snake_cw },
    656     { 11, &fbpoe_snake_ccw },
    657     { 12, &fbpoe_snake_cw },
    658     { 13, &fbpoe_snake_ccw },
    659     { 14, &fbpoe_snake_cw },
    660     { 15, &fbpoe_snake_ccw },
    661     { 16, &fbpoe_snake_cw },
    662     { 17, &fbpoe_snake_ccw },
    663     { 18, &fbpoe_snake_cw },
    664     { 19, &fbpoe_snake_ccw },
    665     { 20, &fbpoe_snake_cw },
    666     { 21, &fbpoe_snake_ccw },
    667     { 22, &fbpoe_snake_cw },
    668     { 23, &fbpoe_snake_ccw },
    669     { 24, &fbpoe_10ge_u0_snake_cw },
    670     { 25, &fbpoe_10ge_u0_snake_cw },
    671     { 24, &fbpoe_10ge_u1_snake_cw },
    672     { 25, &fbpoe_10ge_u1_snake_cw },
    673 };
    674 
    675 /*
    676  * LM_FB48 uses 2 snakes, one per GE port on 56504.
    677  * For even port numbers they go clockwise and for odd port 
    678  * numbers they go counter-clockwise.
    679  */
    680 STATIC system_snake_path_t lm_fb48_snake_cw  = {
    681     2, 
    682     183,
    683     0,
    684     { /*   u  sm  sp  dm  dp  flags */
    685         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    686         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    687     }
    688 };
    689 
    690 STATIC system_snake_path_t lm_fb48_snake_ccw = {
    691     2,
    692     183,
    693     0,
    694     { /*   u  sm  sp  dm  dp  flags */
    695         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    696         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    697     }              
    698 };
    699 
    700 STATIC system_snake_list_t lmfb48_snake_test[] = {
    701     {  0, &lm_fb48_snake_cw },
    702     {  1, &lm_fb48_snake_ccw },
    703     {  2, &lm_fb48_snake_cw },
    704     {  3, &lm_fb48_snake_ccw },
    705     {  4, &lm_fb48_snake_cw },
    706     {  5, &lm_fb48_snake_ccw },
    707     {  6, &lm_fb48_snake_cw },
    708     {  7, &lm_fb48_snake_ccw },
    709     {  8, &lm_fb48_snake_cw },
    710     {  9, &lm_fb48_snake_ccw },
    711     { 10, &lm_fb48_snake_cw },
    712     { 11, &lm_fb48_snake_ccw },
    713     { 12, &lm_fb48_snake_cw },
    714     { 13, &lm_fb48_snake_ccw },
    715     { 14, &lm_fb48_snake_cw },
    716     { 15, &lm_fb48_snake_ccw },
    717     { 16, &lm_fb48_snake_cw },
    718     { 17, &lm_fb48_snake_ccw },
    719     { 18, &lm_fb48_snake_cw },
    720     { 19, &lm_fb48_snake_ccw },
    721     { 20, &lm_fb48_snake_cw },
    722     { 21, &lm_fb48_snake_ccw },
    723     { 22, &lm_fb48_snake_cw },
    724     { 23, &lm_fb48_snake_ccw },
    725 };
    726 
    727 /*
    728  * Felix 48 port uses 2 snakes per port. The platform has 2
    729  * felix devices (24 FE, 1 GE and 1 10GE port). The 2 devices are
    730  * connected through HG0 port.
    731  */
    732 STATIC system_snake_path_t felix48p_snake_cw  = {
    733     2, 
    734     483,
    735     0,
    736     { /*   u  sm  sp  dm  dp  flags */
    737         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    738         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    739     }
    740 };
    741 
    742 STATIC system_snake_path_t felix48p_snake_ccw = {
    743     2,
    744     483,
    745     0,
    746     { /*   u  sm  sp  dm  dp  flags */
    747         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    748         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    749     }              
    750 };
    751 
    752 STATIC system_snake_path_t felix48p_snake_ge_cw  = {
    753     2, 
    754     183,
    755     0,
    756     { /*   u  sm  sp  dm  dp  flags */
    757         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    758         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    759     }
    760 };
    761 
    762 STATIC system_snake_path_t felix48p_snake_ge_ccw = {
    763     2,
    764     183,
    765     0,
    766     { /*   u  sm  sp  dm  dp  flags */
    767         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    768         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    769     }              
    770 };
    771 
    772 STATIC system_snake_path_t felix48p_10ge_snake_cw  = {
    773     2, 
    774     480,
    775     0,
    776     { /*   u  sm  sp  dm  dp  flags */
    777         {  0,  0,  27,  1,  27, SS_DP_NOEXT },
    778         {  1,  1,  27,  0,  27, SS_DP_NOEXT },
    779     }
    780 };
    781 
    782 STATIC system_snake_list_t felix48p_snake_test[] = {
    783     {  0, &felix48p_snake_cw },
    784     {  1, &felix48p_snake_ccw },
    785     {  2, &felix48p_snake_cw },
    786     {  3, &felix48p_snake_ccw },
    787     {  4, &felix48p_snake_cw },
    788     {  5, &felix48p_snake_ccw },
    789     {  6, &felix48p_snake_cw },
    790     {  7, &felix48p_snake_ccw },
    791     {  8, &felix48p_snake_cw },
    792     {  9, &felix48p_snake_ccw },
    793     { 10, &felix48p_snake_cw },
    794     { 11, &felix48p_snake_ccw },
    795     { 12, &felix48p_snake_cw },
    796     { 13, &felix48p_snake_ccw },
    797     { 14, &felix48p_snake_cw },
    798     { 15, &felix48p_snake_ccw },
    799     { 16, &felix48p_snake_cw },
    800     { 17, &felix48p_snake_ccw },
    801     { 18, &felix48p_snake_cw },
    802     { 19, &felix48p_snake_ccw },
    803     { 20, &felix48p_snake_cw },
    804     { 21, &felix48p_snake_ccw },
    805     { 22, &felix48p_snake_cw },
    806     { 23, &felix48p_snake_ccw },
    807     { 24, &felix48p_snake_ge_cw },
    808     { 25, &felix48p_snake_ge_ccw },
    809     { 27, &felix48p_10ge_snake_cw },
    810 };
    811 
    812 /*
    813  * Raptor/Raven cascase platform with slave connected over EB bus.
    814  * special config setting needed ss_ignore_pbmp=0x3e so that we 
    815  * dont mess around with the link ports as eb slave depends on that.
    816  */
    817 
    818 STATIC system_snake_path_t raptor_eb_snake_cw  = {
    819     2, 
    820     483,
    821     0,
    822     { /*   u  sm  sp  dm  dp  flags */
    823         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    824         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    825     }
    826 };
    827 
    828 STATIC system_snake_path_t raptor_eb_ge1_snake_cw  = {
    829     2, 
    830     1600,
    831     1,
    832     { /*   u  sm  sp  dm  dp  flags */
    833         {  0,  0,  2,  1,  2, SS_DP_NOEXT },
    834         {  1,  1,  2,  0,  2, SS_DP_NOEXT },
    835     }
    836 };
    837 STATIC system_snake_path_t raptor_eb_ge4_snake_cw  = {
    838     2, 
    839     1600,
    840     1,
    841     { /*   u  sm  sp  dm  dp  flags */
    842         {  0,  0,  5,  1,  5, SS_DP_NOEXT },
    843         {  1,  1,  5,  0,  5, SS_DP_NOEXT },
    844     }
    845 };
    846 
    847 STATIC system_snake_list_t raptor_eb_snake_test[] = {
    848     {  6, &raptor_eb_snake_cw },
    849     {  7, &raptor_eb_snake_cw },
    850     {  8, &raptor_eb_snake_cw },
    851     {  9, &raptor_eb_snake_cw },
    852     { 10, &raptor_eb_snake_cw },
    853     { 11, &raptor_eb_snake_cw },
    854     { 12, &raptor_eb_snake_cw },
    855     { 13, &raptor_eb_snake_cw },
    856     { 14, &raptor_eb_snake_cw },
    857     { 15, &raptor_eb_snake_cw },
    858     { 16, &raptor_eb_snake_cw },
    859     { 17, &raptor_eb_snake_cw },
    860     { 18, &raptor_eb_snake_cw },
    861     { 19, &raptor_eb_snake_cw },
    862     { 20, &raptor_eb_snake_cw },
    863     { 21, &raptor_eb_snake_cw },
    864     { 22, &raptor_eb_snake_cw },
    865     { 23, &raptor_eb_snake_cw },
    866     { 24, &raptor_eb_snake_cw },
    867     { 25, &raptor_eb_snake_cw },
    868     { 26, &raptor_eb_snake_cw },
    869     { 27, &raptor_eb_snake_cw },
    870     { 28, &raptor_eb_snake_cw },
    871     { 29, &raptor_eb_snake_cw },
    872     {  2, &raptor_eb_ge1_snake_cw },
    873     {  5, &raptor_eb_ge4_snake_cw },
    874 };
    875 
    876 /*
    877  * In Hurricane, Port 1 is reserved port..
    878  * Hu uses 2 ports per snake - one per unit.
    879  * even ports go clockwise and odd ports counterclockwise
    880  * Ext snake uses one cw and one ccw
    881  * for SFP ports, In unit0 it is 26 & 27, in Unit 1 it is 28 & 29
    882  */
    883 STATIC system_snake_path_t hu_48p_snake_cw  = {
    884     2, 
    885     183,
    886     0,
    887     { /*   u  sm  sp  dm  dp  flags */
    888         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    889         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    890     }
    891 };
    892 
    893 STATIC system_snake_path_t hu_48p_snake_ccw  = {
    894     2, 
    895     183,
    896     0,
    897     { /*   u  sm  sp  dm  dp  flags */
    898         {  1,  1,  0,  0,  0, SS_SP_PATH | SS_DP_PATH },
    899         {  0,  0,  0,  1,  0, SS_SP_PATH | SS_DP_PATH },
    900     }
    901 };
    902 
    903 STATIC system_snake_path_t hu_48p_snake_u0  = {
    904     1, 
    905     183,
    906     0,
    907     { /*   u  sm  sp  dm  dp  flags */
    908         {  0,  0,  0,  0,  0, SS_SP_PATH | SS_DP_PATH},
    909     }
    910 };
    911 
    912 STATIC system_snake_path_t hu_48p_snake_u1  = {
    913     1,
    914     183,
    915     1,
    916     { /*   u  sm  sp  dm  dp  flags */
    917         {  1,  1,  0,  1,  0, SS_SP_PATH | SS_DP_PATH},
    918     }
    919 };
    920 
    921 STATIC system_snake_list_t hurricane_ge_48p_snake_test[] = {
    922     {  2, &hu_48p_snake_cw },
    923     {  3, &hu_48p_snake_ccw },
    924     {  4, &hu_48p_snake_cw },
    925     {  5, &hu_48p_snake_ccw },
    926     {  6, &hu_48p_snake_cw },
    927     {  7, &hu_48p_snake_ccw },
    928     {  8, &hu_48p_snake_cw },
    929     {  9, &hu_48p_snake_ccw },
    930     {  10, &hu_48p_snake_cw },
    931     {  11, &hu_48p_snake_ccw },
    932     {  12, &hu_48p_snake_cw },
    933     {  13, &hu_48p_snake_ccw },
    934     {  14, &hu_48p_snake_cw },
    935     {  15, &hu_48p_snake_ccw },
    936     {  16, &hu_48p_snake_cw },
    937     {  17, &hu_48p_snake_ccw },
    938     {  18, &hu_48p_snake_cw },
    939     {  19, &hu_48p_snake_ccw },
    940     {  20, &hu_48p_snake_cw },
    941     {  21, &hu_48p_snake_ccw },
    942     {  22, &hu_48p_snake_cw },
    943     {  23, &hu_48p_snake_ccw },
    944     {  24, &hu_48p_snake_cw },
    945     {  25, &hu_48p_snake_ccw },
    946     {  26, &hu_48p_snake_u1 },
    947     {  27, &hu_48p_snake_u1 },
    948     {  28, &hu_48p_snake_u0 },
    949     {  29, &hu_48p_snake_u0 },
    950 };
    951 
    952 STATIC system_snake_list_t hurricane_fe_48p_snake_test[] = {
    953     {  2, &hu_48p_snake_cw },
    954     {  3, &hu_48p_snake_ccw },
    955     {  4, &hu_48p_snake_cw },
    956     {  5, &hu_48p_snake_ccw },
    957     {  6, &hu_48p_snake_cw },
    958     {  7, &hu_48p_snake_ccw },
    959     {  8, &hu_48p_snake_cw },
    960     {  9, &hu_48p_snake_ccw },
    961     {  10, &hu_48p_snake_cw },
    962     {  11, &hu_48p_snake_ccw },
    963     {  12, &hu_48p_snake_cw },
    964     {  13, &hu_48p_snake_ccw },
    965     {  14, &hu_48p_snake_cw },
    966     {  15, &hu_48p_snake_ccw },
    967     {  16, &hu_48p_snake_cw },
    968     {  17, &hu_48p_snake_ccw },
    969     {  18, &hu_48p_snake_cw },
    970     {  19, &hu_48p_snake_ccw },
    971     {  20, &hu_48p_snake_cw },
    972     {  21, &hu_48p_snake_ccw },
    973     {  22, &hu_48p_snake_cw },
    974     {  23, &hu_48p_snake_ccw },
    975     {  24, &hu_48p_snake_cw },
    976     {  25, &hu_48p_snake_ccw },
    977     {  26, &hu_48p_snake_u1 },
    978     {  27, &hu_48p_snake_u1 },
    979 };
    980 
    981 /*
    982  * Finally, all boards together
    983  */
    984 STATIC system_snake_list_t *ss_snake_table[SS_SYSID_NUM] = {
    985     firebolt_snake_test,
    986     fbpoe_snake_test,
    987     lmfb48_snake_test,
    988     felix48p_snake_test,
    989     raptor_eb_snake_test,
    990     hurricane_ge_48p_snake_test,
    991     hurricane_fe_48p_snake_test,
    992 };
    993 
    994 
    995 STATIC system_snake_info_t ssi;
    996 
    997 STATIC bcm_port_config_t pcfg[SOC_MAX_NUM_DEVICES];
    998 
    999 STATIC int
   1000 ss_unit_setup(system_snake_opts_t *opts, int unit)
   1001 {
   1002     int                   rv;
   1003     bcm_port_t            port, dport;
   1004     bcm_pbmp_t            vlan_pbm;
   1005     bcm_vlan_t            vlan;
   1006     pbmp_t                ss_pbm, ignore_pbm;
   1007 
   1008     if (opts->verbose) {
   1009         cli_out("Configuring Ethernet ports on unit %d (%s)\n", 
   1010                 unit, SOC_UNIT_NAME(unit));
   1011     }
   1012 
   1013     if (bcm_port_config_get(unit, &pcfg[unit]) != BCM_E_NONE) {
   1014         cli_out("Error: bcm ports not initialized\n");
   1015         return (-1);
   1016     }
   1017 
   1018     if ((rv = bcm_vlan_destroy_all(unit)) < 0) {
   1019         cli_out("Could not destroy existing VLANs: %s\n",
   1020                 bcm_errmsg(rv));
   1021         return (-1);
   1022     }
   1023 
   1024     BCM_PBMP_ASSIGN(vlan_pbm, pcfg[unit].all);
   1025     ss_pbm = pcfg[unit].e;
   1026     if (soc_property_get_str(unit, spn_SS_IGNORE_PBMP)) {
   1027         ignore_pbm = soc_property_get_bcm_pbmp(unit, spn_SS_IGNORE_PBMP, 0);
   1028         BCM_PBMP_REMOVE(ss_pbm, ignore_pbm);
   1029         cli_out("Removed ignore_pbm from valid ports \n");
   1030     }
   1031     DPORT_BCM_PBMP_ITER(unit, ss_pbm, dport, port) {
   1032         if (opts->verbose) {
   1033             cli_out("\tConfiguring port %s\n", BCM_PORT_NAME(unit, port));
   1034         }
   1035 
   1036         /* Note Ingress Etherport # = path # for now */
   1037         vlan = SS_VLAN_BASE + port;
   1038         if (((rv = bcm_vlan_create(unit, vlan)) < 0) &&
   1039             (rv != BCM_E_EXISTS) ) {
   1040             test_error(unit,
   1041                        "Could not create VLAN %d: %s\n",
   1042                        vlan, bcm_errmsg(rv));
   1043             return (-1);
   1044         }
   1045 
   1046         if ((rv = bcm_vlan_port_add(unit, vlan, vlan_pbm, vlan_pbm)) < 0) {
   1047             test_error(unit,
   1048                        "Could not add test ports to VLAN %d: %s\n",
   1049                        vlan, bcm_errmsg(rv));
   1050             return (-1);
   1051         }
   1052  
   1053         if ((rv = bcm_port_untagged_vlan_set(unit, port, vlan)) < 0) {
   1054             test_error(unit,
   1055                        "Could not set port %s to tag with VLAN %d: %s\n",
   1056                        BCM_PORT_NAME(unit, port), vlan, bcm_errmsg(rv));
   1057             return (-1);
   1058         }
   1059 
   1060         if (opts->mode == SS_MODE_MAC) {
   1061             if ((rv = bcm_port_loopback_set(unit, port,
   1062                                             BCM_PORT_LOOPBACK_MAC)) < 0) {
   1063                 test_error(unit,
   1064                            "Port %s: Failed to set MAC loopback: %s\n",
   1065                            BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1066                 return(-1);                     /* In case they continue */
   1067             }
   1068         } else if (opts->mode == SS_MODE_PHY) {
   1069             if ((rv = bcm_port_loopback_set(unit, port,
   1070                                             BCM_PORT_LOOPBACK_PHY)) < 0) {
   1071                 test_error(unit,
   1072                            "Port %s: Failed to set PHY loopback: %s\n",
   1073                            BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1074                 return(-1);                     /* In case they continue */
   1075             }
   1076         } else {
   1077             /* Else normal port operation for SS_MODE_EXT, where  */
   1078             /* ports are wired 1-2, 3-4, 5-6 etc.                 */
   1079  
   1080             assert(opts->mode == SS_MODE_EXT);
   1081         }
   1082 
   1083         if ((rv = bcm_port_enable_set(unit, port, TRUE)) < 0) {
   1084             test_error(unit,
   1085                        "Port %s: Failed to enable ports: %s\n",
   1086                        BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1087             return(-1);                         /* In case they continue */
   1088         }
   1089 
   1090         if ((rv = bcm_port_learn_set(unit, port,
   1091                                      BCM_PORT_LEARN_FWD)) < 0) {
   1092             test_error(unit,
   1093                        "Unable to set learn state: port %s: %s\n",
   1094                        BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1095             return (-1);
   1096         }
   1097 
   1098         /* Use speed set by rc unless overridden on cmd line. */
   1099         if (!BCM_PBMP_MEMBER(pcfg[unit].xe, port)) {
   1100             int speed = ss_speed_mbits[opts->speed];
   1101 
   1102             if (opts->speed == SS_SPEED_DEFAULT) {
   1103                 if ((rv = bcm_port_speed_max(unit, port, &speed)) < 0) {
   1104                     test_error(unit,
   1105                                "Port %s: Failed to get max port speed: %s\n",
   1106                                BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1107                     return(-1);                     /* In case they continue */
   1108                 }
   1109             }
   1110 
   1111             /*
   1112              * Set speed in any case.  Otherwise, the internal PHY/MAC
   1113              * will not necessarily be programmed correctly since linkscan
   1114              * is no longer scanning the port after it is in loopback.
   1115              */
   1116             if ((rv = bcm_port_speed_set(unit, port, speed)) < 0) {
   1117                 test_error(unit,
   1118                            "Port %s: Failed to set port speed: %s\n",
   1119                            BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1120                 return(-1);                     /* In case they continue */
   1121             }
   1122         }
   1123 
   1124         /* Always use full duplex for ss. */
   1125         if ((rv = bcm_port_duplex_set(unit, port, 
   1126                                       BCM_PORT_DUPLEX_FULL)) < 0) {
   1127             test_error(unit,
   1128                        "Port %s: Failed to set port duplex: %s\n",
   1129                        BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1130             return(-1);                     /* In case they continue */
   1131         }
   1132 
   1133         if (opts->mode == SS_MODE_EXT) {
   1134             /* Always use full duplex for ss. */
   1135             if ((rv = bcm_port_advert_set(unit, port, 
   1136                                           BCM_PORT_ABIL_FD)) < 0) {
   1137                 test_error(unit,
   1138                            "Port %s: Failed to set port duplex advert: %s\n",
   1139                            BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1140                 return(-1);                     /* In case they continue */
   1141             }
   1142             if (opts->speed != SS_SPEED_DEFAULT) {
   1143                 /* Use cmd line speed */
   1144                 if ((rv =
   1145                      bcm_port_advert_set(unit, port, 
   1146                                          ss_speed_abil[opts->speed])) < 0) {
   1147                     test_error(unit,
   1148                                "Port %s: "
   1149                                "Failed to set port speed advert: %s\n",
   1150                                BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1151                     return(-1);                     /* In case they continue */
   1152                 }
   1153             }
   1154             /* Restart autonegotiation */
   1155             if ((rv = bcm_port_autoneg_set(unit, port, 
   1156                                            TRUE)) < 0) {
   1157                 test_error(unit,
   1158                            "Port %s: Failed to restart autonegotiation: %s\n",
   1159                            BCM_PORT_NAME(unit, port), bcm_errmsg(rv));
   1160                 return(-1);                     /* In case they continue */
   1161             }
   1162         } /* SS_MODE_EXT advert and autoneg */
   1163 
   1164     } /* For each port */
   1165 
   1166     return (0);
   1167 }        
   1168 
   1169 STATIC void
   1170 ss_set_packet_length_increment(system_snake_opts_t *opts)
   1171 {
   1172     int                   snake;
   1173     int                   sysid = opts->sysid;
   1174     int                   snake_num  = ss_num_paths[sysid];
   1175     system_snake_list_t  *snake_list = ss_snake_table[sysid];
   1176 
   1177     for (snake = 0; snake < snake_num; snake++) {
   1178         snake_list[snake].snake_path->packet_length_inc = opts->pli;
   1179     }
   1180 }
   1181 
   1182 STATIC int
   1183 ss_port_interconnect_define(system_snake_opts_t *opts)
   1184 {
   1185     lb2s_port_connect_t  *pi;
   1186     int                   snake;
   1187     system_snake_list_t  *snake_list;
   1188     system_snake_path_t  *snake_path;
   1189     int                   snake_num;
   1190     int                   snake_len;
   1191     int                   snake_port;
   1192     int                   i;
   1193     int                   sysid = opts->sysid;
   1194 
   1195     snake_list = ss_snake_table[sysid];
   1196     snake_num  = ss_num_paths[sysid];
   1197     
   1198     for (snake = 0; snake < snake_num; snake++) {
   1199         /*
   1200          * Define snake interconnects
   1201          */
   1202         if (opts->verbose) {
   1203             cli_out("Setting up snake %d\n", snake);
   1204         }
   1205 
   1206         snake_path = snake_list[snake].snake_path;
   1207         snake_port = snake_list[snake].snake_port;
   1208         snake_len  = snake_path->conn_count;
   1209 
   1210         for (i = 0; i < snake_len; i++) {
   1211             pi = &ssi.snake_pi[snake][i];
   1212             sal_memset(pi, 0, sizeof(*pi));
   1213 
   1214             pi->src_modid  = snake_path->conn[i].src_mod;
   1215             pi->this_port  = snake_path->conn[i].src_port;
   1216             pi->dst_modid  = snake_path->conn[i].dst_mod;
   1217             pi->to_port    = snake_path->conn[i].dst_port;
   1218             pi->added_vlan = SS_VLAN_BASE + snake_port;
   1219             ENET_SET_MACADDR(pi->src_mac, ss_mac_src[snake]);
   1220             ENET_SET_MACADDR(pi->dst_mac, ss_mac_dst[snake]);
   1221 
   1222             if (snake_path->conn[i].flags & SS_SM_PATH) { 
   1223                 pi->src_modid += snake_port; 
   1224             }
   1225 
   1226             if (snake_path->conn[i].flags & SS_SP_PATH) { 
   1227                 pi->this_port += snake_port; 
   1228             }
   1229             
   1230             if (snake_path->conn[i].flags & SS_DM_PATH) { 
   1231                 pi->dst_modid += snake_port; 
   1232             }
   1233 
   1234             if (snake_path->conn[i].flags & SS_DP_PATH) {
   1235                 pi->to_port += snake_port;
   1236                 if ((opts->mode == SS_MODE_EXT) ||
   1237                     (snake_path->conn[i].flags & SS_DP_FORCE)) {
   1238                     if (!(snake_path->conn[i].flags & SS_DP_NOEXT)) {
   1239                         pi->to_port ^= 1;
   1240                     }
   1241                 }
   1242             }
   1243             
   1244             pi->valid_info = TRUE;
   1245 
   1246             if (opts->verbose) {
   1247                 cli_out("\t%02d.%02d -> %02d.%02d\n", 
   1248                         pi->src_modid, pi->this_port,
   1249                         pi->dst_modid, pi->to_port);
   1250             }
   1251         }
   1252 
   1253         /*
   1254          * Define the CPU return path (for each snake it is the first unit 
   1255          * in snake's definition that is used for cell injection and return)
   1256          */
   1257         pi = &ssi.cmic_return_pi[snake];
   1258         sal_memset(pi, 0, sizeof(*pi));
   1259 
   1260         pi->src_modid  = snake_path->conn[0].src_mod;
   1261         pi->this_port  = snake_port;
   1262         pi->dst_modid  = snake_path->conn[0].src_mod;
   1263         pi->to_port    = CMIC_PORT(snake_path->conn[0].unit);
   1264         pi->added_vlan = SS_VLAN_BASE + snake_port;
   1265         ENET_SET_MACADDR(pi->src_mac, ss_mac_src[snake]);
   1266         ENET_SET_MACADDR(pi->dst_mac, ss_mac_dst[snake]);
   1267         pi->valid_info = TRUE;
   1268 
   1269         if (opts->verbose) {
   1270             cli_out("\tReturn path via unit %d\n", snake_path->conn[0].unit);
   1271         }
   1272     }
   1273 
   1274     return (0);
   1275 }
   1276 
   1277 STATIC int
   1278 ss_port_interconnect_execute(system_snake_opts_t *opts)
   1279 {
   1280     lb2s_port_connect_t  *pi;
   1281     int                   snake;
   1282     int                   snake_len;
   1283     system_snake_path_t  *snake_path; 
   1284     int                   i;
   1285     int                   rv;
   1286     int                   unit = 0;
   1287     int                   sysid      = opts->sysid;
   1288     system_snake_list_t  *snake_list = ss_snake_table[sysid];
   1289     int                   snake_num  = ss_num_paths[sysid];
   1290     
   1291     for (snake = 0; snake < snake_num; snake++) {
   1292         if (opts->verbose) {
   1293             cli_out("Executing connections for snake %d\n", snake);
   1294         }
   1295 
   1296         snake_path = snake_list[snake].snake_path;
   1297         snake_len  = snake_path->conn_count;
   1298 
   1299         for (i = 0; i < snake_len; i++) {
   1300             unit = snake_path->conn[i].unit;
   1301             pi   = &ssi.snake_pi[snake][i];
   1302 
   1303             if (opts->verbose) {
   1304                 cli_out("\t%02d.%02d(%02d) -> %02d.%02d\n", 
   1305                         pi->src_modid, pi->this_port,
   1306                         pi->added_vlan - SS_VLAN_BASE,
   1307                         pi->dst_modid, pi->to_port);
   1308             }
   1309 
   1310             rv = lbu_connect_ports(unit, pi, TRUE);
   1311             if (rv < 0) {
   1312                 test_error(unit,
   1313                            "Port %s: Failed to connect to %02d.%02d: %s\n",
   1314                            BCM_PORT_NAME(unit, pi->this_port),
   1315                            pi->dst_modid, pi->to_port, bcm_errmsg(rv));
   1316                 return (-1);
   1317             }
   1318         }
   1319     }
   1320 
   1321     return (0);
   1322 }
   1323 
   1324 STATIC void
   1325 ss_io_units_find(system_snake_opts_t *opts)
   1326 {
   1327     int                   unit;
   1328     int                   snake;
   1329     system_snake_path_t  *snake_path;
   1330     int                   num_packets;
   1331     int                   sysid = opts->sysid;
   1332     system_snake_list_t  *snake_list = ss_snake_table[sysid];
   1333     int                   snake_num  = ss_num_paths[sysid];
   1334 
   1335     SS_UNIT_ITER(sysid, unit) {
   1336         num_packets = 0;
   1337         for (snake = 0; snake < snake_num; snake++) {
   1338             snake_path =  snake_list[snake].snake_path;
   1339             /* Check if the snakes originates at the given unit */
   1340             if (snake_path->conn[0].unit == unit) {
   1341                 num_packets += SS_PACKETS_PER_PATH(snake_path);
   1342             }
   1343         }
   1344 
   1345         ssi.num_packets[unit] = num_packets;
   1346  
   1347         if (num_packets == 0) {
   1348             continue;
   1349         }
   1350 
   1351         ssi.io_unit[ssi.io_unit_num++] = unit;
   1352     }
   1353 
   1354     if (opts->verbose) {
   1355         cli_out("%d units found\n", ssi.io_unit_num);
   1356     }
   1357 }
   1358 
   1359 STATIC int
   1360 ss_packet_alloc(system_snake_opts_t *opts, int unit)
   1361 {
   1362     int num_packets = ssi.num_packets[unit];
   1363 
   1364     /* Allocate packet space */
   1365 
   1366     if (opts->verbose) {
   1367         cli_out("%d Tx packets for unit %d\n", num_packets, unit);
   1368     }
   1369     
   1370     bcm_pkt_blk_alloc(unit, num_packets,SS_PACKET_LENGTH_MAX,
   1371                       BCM_TX_CRC_REGEN, &ssi.lw[unit].tx_pkts);
   1372     if (!ssi.lw[unit].tx_pkts) {
   1373         cli_out("Unable to allocate tx packet memory\n");
   1374         return BCM_E_MEMORY;
   1375     }
   1376         
   1377     if (opts->verbose) {
   1378         cli_out("%d Rx packets for unit %d\n", num_packets, unit);
   1379     }
   1380 
   1381     ssi.lw[unit].rx_pkts = sal_alloc(num_packets * sizeof(bcm_pkt_t), 
   1382                                      "SS rx pkts");
   1383     if (!ssi.lw[unit].rx_pkts) {
   1384         bcm_pkt_blk_free(unit, ssi.lw[unit].tx_pkts, num_packets);
   1385         cli_out("Unable to allocate rx packet memory\n");
   1386         return BCM_E_MEMORY;
   1387     }
   1388         
   1389     sal_memset(ssi.lw[unit].rx_pkts, 0, num_packets * sizeof(bcm_pkt_t));
   1390         
   1391     if (opts->verbose) {
   1392         cli_out("%d Tx packet match markers for unit %d\n", num_packets, unit);
   1393     }
   1394         
   1395     ssi.lw[unit].tx_pkt_match = sal_alloc(num_packets * sizeof(int), 
   1396                                           "SS TX match markers");
   1397     if (!ssi.lw[unit].tx_pkt_match) {
   1398         bcm_pkt_blk_free(unit, ssi.lw[unit].tx_pkts, num_packets);
   1399         sal_free(ssi.lw[unit].rx_pkts);
   1400         return BCM_E_MEMORY;
   1401     }
   1402         
   1403     sal_memset(ssi.lw[unit].tx_pkt_match, 0, num_packets * sizeof(int));
   1404     
   1405     return (0);
   1406 }
   1407 
   1408 STATIC void
   1409 ss_tx_packet_fill(system_snake_opts_t *opts, int unit)
   1410 {
   1411     int                   snake;
   1412     lb2s_port_connect_t  *pi;
   1413     int                   length;
   1414     int                   cur_offset;
   1415     uint8                *sequence_p;
   1416     bcm_pkt_t            *pkt;
   1417     enet_hdr_t           *eh;
   1418     int                   pkt_idx    = 0;
   1419     uint8                 seq_no     = SS_SEQUENCE_BASE;
   1420     uint32                pattern    = SS_PATTERN_BASE;
   1421     int                   sysid      = opts->sysid;
   1422     system_snake_list_t  *snake_list = ss_snake_table[sysid];
   1423     int                   snake_num  = ss_num_paths[sysid];
   1424         
   1425     for (snake = 0; snake < snake_num; snake++) {
   1426         if (snake_list[snake].snake_path->conn[0].unit != unit) {
   1427             continue;
   1428         }
   1429         pi = &(ssi.snake_pi[snake][0]);
   1430         for (length = SS_PACKET_LENGTH_MIN; length <= SS_PACKET_LENGTH_MAX; 
   1431              length += snake_list[snake].snake_path->packet_length_inc) {
   1432             pkt = ssi.lw[unit].tx_pkts[pkt_idx];
   1433             pkt->cos = SS_COS;
   1434             /* For now, internal priority matches COS (or v.v.) */
   1435             pkt->prio_int = SS_COS;
   1436             pkt->opcode = BCM_HG_OPCODE_UC;
   1437             pkt->pkt_data[0].len = length;
   1438             BCM_PBMP_CLEAR(pkt->tx_pbmp);
   1439             BCM_PBMP_PORT_ADD(pkt->tx_pbmp, pi->to_port);
   1440             BCM_PBMP_CLEAR(pkt->tx_upbmp);
   1441             BCM_PBMP_PORT_ADD(pkt->tx_upbmp, pi->to_port);
   1442 
   1443             eh = (enet_hdr_t *)BCM_PKT_DMAC(pkt);
   1444                 
   1445             /* Write source/destination MAC address */
   1446             ENET_SET_MACADDR(&eh->en_dhost, pi->dst_mac);
   1447             ENET_SET_MACADDR(&eh->en_shost, pi->src_mac);
   1448                 
   1449             /* Write VLAN tag (16 + 16 bits) and sequence number (32 bits) */
   1450             packet_store((uint8 *)&eh->en_tag_tpid, 2, 0x8100 << 16, 0);
   1451             packet_store((uint8 *)&eh->en_tag_ctrl, 2,
   1452                          VLAN_CTRL(0, 0, pi->added_vlan) << 16, 0);
   1453             packet_store((uint8*)eh + 16, 4, seq_no++, 0);
   1454 
   1455             /*
   1456              * Fill data from after header & seq # to end of packet.  
   1457              * Byte data starts with the pattern MSByte through LSByte 
   1458              * and recycles.
   1459              */
   1460             cur_offset = 20;
   1461             pattern = packet_store((uint8*)eh + cur_offset, 
   1462                                    pkt->pkt_data[0].len - cur_offset,
   1463                                    pattern, SS_PATTERN_INC);
   1464 
   1465             /* Store the sequence number of the packet */
   1466             sequence_p = (uint8 *)eh + LB2_ID_POS;
   1467             *sequence_p = seq_no;
   1468                 
   1469             pkt_idx++;
   1470         }
   1471     }
   1472 }
   1473 
   1474 STATIC int
   1475 ss_lbu_monitor_start(int unit)
   1476 {
   1477     ssi.lw[unit].sema = sal_sem_create("ss-sema", sal_sem_BINARY, 0);
   1478     if (ssi.lw[unit].sema == NULL) {
   1479         return (-1);
   1480     }
   1481 
   1482     ssi.lw[unit].sema_woke = FALSE;
   1483         
   1484     /* Now that all mems are safely created, fire off the handler */
   1485     /* Let rx handler ignore packets until testing */
   1486     ssi.lw[unit].expect_pkts = FALSE; 
   1487     ssi.lw[unit].rx_pkt_cnt = 0;
   1488     ssi.lw[unit].tx_ppt = ssi.num_packets[unit]; /* For use in callback */
   1489     if (lbu_port_monitor_task(unit, lbu_rx_callback, &(ssi.lw[unit])) < 0) {
   1490         return (-1);
   1491     }
   1492         
   1493     /* Wiring up required data to fake out the lbu subsystem */
   1494     ssi.lw[unit].current_test_type = LB2_TT_SNAKE;
   1495     ssi.lw[unit].set_up = TRUE;
   1496     ssi.lw[unit].cur_params = &(ssi.lw[unit].params[LB2_TT_SNAKE]);
   1497     ssi.lw[unit].cur_params->loopback = LB2_MODE_PHY;
   1498 
   1499     return(0);
   1500 }
   1501 
   1502 STATIC int
   1503 system_snake_init(system_snake_opts_t *opts)
   1504 {
   1505     int                   unit = 0, rv;
   1506     int                   i;
   1507     bcm_pbmp_t            all_ethernets_pbm, ignore_pbm;
   1508     int                   sysid = opts->sysid;
   1509 #ifndef NO_SAL_APPL
   1510     char                 *init_soc_file;
   1511 #endif
   1512 
   1513     if (opts->verbose) {
   1514         cli_out("Initializing system snake\n");
   1515     }
   1516 
   1517     memset(&ssi, 0, sizeof(ssi));
   1518 
   1519     SS_UNIT_ITER(sysid, unit) {
   1520         /*
   1521          * Load system defaults from rc.soc
   1522          */
   1523 
   1524         sh_swap_unit_vars(unit);
   1525 
   1526 #ifndef NO_SAL_APPL
   1527         if (diag_rc_load(unit) != CMD_OK) {
   1528             cli_out("Test: ERROR: RC init script "
   1529                     "for system snake test failed\n");
   1530             return (-1);
   1531         }
   1532 
   1533         /*
   1534          * Load system snake soc dcript.
   1535          */
   1536         if ((init_soc_file = ss_init_file[sysid]) &&
   1537             sh_rcload_file(unit, NULL, init_soc_file, FALSE) != CMD_OK) {
   1538             cli_out("Test: ERROR: %s init script "
   1539                     "for system snake test failed\n", SS_SOC_SCRIPT);
   1540             return (-1);
   1541         }
   1542 #endif
   1543 
   1544         ssi.stats[unit] =
   1545             sal_alloc(SOC_MAX_NUM_PORTS * sizeof(lb2_port_stat_t),
   1546                       "SS statistics");
   1547         if (!ssi.stats[unit]) {
   1548             cli_out("Unable to allocate statistics memory\n");
   1549             return BCM_E_MEMORY;
   1550         }
   1551         
   1552         /* 
   1553          * Configuring chips for the test 
   1554          */
   1555 
   1556         if (ss_unit_setup(opts, unit) < 0) {
   1557             cli_out("%s: Unit setup failed\n", SOC_UNIT_NAME(unit));
   1558             return (-1);
   1559         }
   1560     }
   1561 
   1562     /* 
   1563      * Wait for restarted links to come up on all e-ports on each unit 
   1564      */
   1565     if (opts->mode == SS_MODE_EXT) {
   1566         cli_out("Checking external links... ");
   1567         SS_UNIT_ITER(sysid, unit) {
   1568             BCM_PBMP_ASSIGN(all_ethernets_pbm, pcfg[unit].e); 
   1569             if (soc_property_get_str(unit, spn_SS_IGNORE_PBMP)) {
   1570                 ignore_pbm = soc_property_get_bcm_pbmp(unit, spn_SS_IGNORE_PBMP, 0);
   1571                 BCM_PBMP_REMOVE(all_ethernets_pbm, ignore_pbm);
   1572             }
   1573             if ((rv = bcm_link_wait(unit,&all_ethernets_pbm, 20000000)) < 0) {
   1574                 test_error(unit,
   1575                            "Unit %d: Failed to complete autonegotiation: %s\n"
   1576                            "Check front panel cables\n",
   1577                            unit, bcm_errmsg(rv));
   1578                 return(-1);                     /* In case they continue */
   1579             }
   1580         }
   1581         cli_out("up\n");
   1582     }
   1583 
   1584     /* 
   1585      * Define port interconnections 
   1586      */
   1587     if ((rv = ss_port_interconnect_define(opts)) < 0) {
   1588         test_error(unit,
   1589                    "Failed to define port interconnects: %s\n",
   1590                    bcm_errmsg(rv));
   1591         return(-1);
   1592     }
   1593 
   1594    /*
   1595     * Execute port interconnections
   1596     */
   1597     if ((rv = ss_port_interconnect_execute(opts)) < 0) {
   1598         test_error(unit,
   1599                    "Failed to execute port interconnects: %s\n",
   1600                    bcm_errmsg(rv));
   1601         return(-1);
   1602     }
   1603 
   1604     /*
   1605      * Find the units that will be used to inject and extract packets
   1606      */
   1607     ss_io_units_find(opts);
   1608 
   1609     for (i = 0; i < ssi.io_unit_num; i++) {
   1610         unit = ssi.io_unit[i];
   1611 
   1612         /*
   1613          * Allocate memory for Tx packets, Rx packets and packet match markers
   1614          */
   1615         if ((rv = ss_packet_alloc(opts, unit)) < 0) {
   1616             test_error(unit,
   1617                        "Failed to allocate Tx or Rx packets: %s\n",
   1618                        bcm_errmsg(rv));
   1619             return (-1);
   1620         }
   1621 
   1622         /*
   1623          * Fill individual Tx packets 
   1624          */
   1625         ss_tx_packet_fill(opts, unit);
   1626 
   1627         /*
   1628          * Start loopback monitors
   1629          */
   1630         if ((rv = ss_lbu_monitor_start(unit)) < 0) {
   1631             test_error(unit,
   1632                        "Failed to start loopback monitor thread: %s\n",
   1633                        bcm_errmsg(rv));
   1634             return (-1);
   1635         }
   1636     }
   1637 
   1638     return 0;
   1639 }
   1640 
   1641 static int
   1642 system_snake_stats(int unit, bcm_pbmp_t bitmap, lb2_port_stat_t stats[])
   1643 {
   1644     /* 
   1645      * NB: We choose "SOC_IS_XGS(unit)" for the third argument so
   1646      * that traffic checking is disabled on fabrics.  This is to
   1647      * prevent complaint on the external loopbacks.
   1648      */
   1649 
   1650     return lbu_snake_stats(unit, bitmap,
   1651                            (SOC_IS_XGS(unit)) ? LB2_MODE_EXT : LB2_MODE_PHY,
   1652                            stats);
   1653 }
   1654 
   1655 int
   1656 system_snake_run(system_snake_opts_t *opts)
   1657 {
   1658     int                   unit, rv, ix, io_unit;
   1659     int                   i, port;
   1660     int                   timer, sleep_time;
   1661     int                   no_packets;
   1662     lb2s_port_connect_t  *pi;
   1663     int                   snake;
   1664     int                   num_packets;
   1665     int                   sysid = opts->sysid;
   1666     system_snake_list_t  *snake_list = ss_snake_table[sysid];
   1667     int                   snake_num  = ss_num_paths[sysid];
   1668 
   1669     /* Counter records init */
   1670     SS_UNIT_ITER(sysid, unit) {
   1671         for (ix = 0; ix < SOC_MAX_NUM_PORTS; ix++) {
   1672             ssi.stats[unit][ix].initialized = FALSE;
   1673         }
   1674 
   1675         BCM_PBMP_ITER(pcfg[unit].port, port) {
   1676             if ((rv = bcm_stat_clear(unit, port)) < 0) {
   1677                 test_error(unit,
   1678                            "Could not clear counters: %s\n",
   1679                            bcm_errmsg(rv));
   1680                 return -1;
   1681             }
   1682         }
   1683 
   1684         /* This is the init call */
   1685         if (system_snake_stats(unit, pcfg[unit].port,
   1686                                ssi.stats[unit]) < 0) {
   1687             lbu_snake_dump_stats(unit, pcfg[unit].port, ssi.stats[unit]);
   1688             return (-1);
   1689         }
   1690     }
   1691 
   1692     /* TX packets */
   1693     if (opts->verbose) {
   1694         cli_out("Transmitting packets\n");
   1695     }
   1696     
   1697     for (i = 0; i < ssi.io_unit_num; i++) {
   1698         io_unit = ssi.io_unit[i];
   1699 
   1700         num_packets = ssi.num_packets[io_unit];
   1701 
   1702         if (opts->verbose) {
   1703             cli_out("\t%d packets to unit %d\n", num_packets, io_unit);
   1704         }
   1705 
   1706         for (ix = 0; ix < num_packets; ix++ ) {
   1707             if ((rv = bcm_tx(io_unit,
   1708                              ssi.lw[io_unit].tx_pkts[ix], NULL)) < 0) {
   1709                 cli_out("System snake TX pkt %d: ERROR: bcm_tx: %s\n", 
   1710                         ix, bcm_errmsg(rv));
   1711             }
   1712         }
   1713     }
   1714 
   1715     cli_out("Running (%d seconds): Speed=%s Mode=%s\n",
   1716             opts->duration, 
   1717             ss_speed_str[opts->speed],
   1718             ss_mode_str[opts->mode]);
   1719 
   1720     /* Wait, monitor counters */
   1721     timer = 0;
   1722     no_packets = 0;
   1723     while (timer < opts->duration) {
   1724         if ((opts->duration - timer) < opts->interval) 
   1725             sleep_time = opts->duration - timer;
   1726         else
   1727             sleep_time = opts->interval;
   1728 
   1729         sal_sleep(sleep_time);
   1730         timer += sleep_time;
   1731         cli_out("Time elapsed:  %d seconds %s\n", timer,
   1732                 (timer>=opts->duration)?"(end of test)":"");
   1733 
   1734         SS_UNIT_ITER(sysid, unit) {
   1735             if (system_snake_stats(unit,
   1736                              pcfg[unit].port, ssi.stats[unit]) < 0) {
   1737                 no_packets = 1;
   1738                 break;
   1739             }
   1740         }
   1741         
   1742         if (no_packets) {
   1743             break;
   1744         }
   1745     }
   1746 
   1747     if (no_packets) {
   1748         SS_UNIT_ITER(sysid, unit) {
   1749             cli_out("Counters for unit %d (%s)\n", unit, SOC_UNIT_NAME(unit));
   1750             system_snake_stats(unit, pcfg[unit].port, ssi.stats[unit]);
   1751             lbu_snake_dump_stats(unit, pcfg[unit].port, ssi.stats[unit]);
   1752         }
   1753 
   1754         cli_out("\nSystem snake test FAILED\n");
   1755         
   1756         return (-1);
   1757     }
   1758         
   1759     /* Let the packets out */
   1760     for (snake = 0 ; snake < snake_num; snake++) {
   1761         int return_unit;
   1762 
   1763         return_unit = io_unit = snake_list[snake].snake_path->conn[0].unit;
   1764         /*
   1765          * For external loopback, we may need to set up the filter on
   1766          * a unit that is different than the one on which the packet was
   1767          * transmitted.
   1768          */
   1769         if (opts->mode == SS_MODE_EXT) {
   1770             return_unit = snake_list[snake].snake_path->return_unit;
   1771         }
   1772 
   1773         ssi.lw[io_unit].unit = io_unit;
   1774         ssi.lw[io_unit].expect_pkts = TRUE;
   1775 
   1776         pi = &(ssi.cmic_return_pi[snake]);
   1777         if (opts->verbose) {
   1778             cli_out("Redirect %d to CPU\n", pi->added_vlan - SS_VLAN_BASE);
   1779         }
   1780         if ((rv = lbu_connect_ports(return_unit, pi, TRUE)) < 0) {
   1781             test_error(io_unit,
   1782                        "CPU redirect failure on snake %d: %s\n",
   1783                        snake, bcm_errmsg(rv));
   1784             return -1;
   1785         }
   1786 
   1787         sal_usleep(SS_INTERPATH_WAIT); /* To let packets drain */
   1788     }
   1789     
   1790     /* Retrieve packets */
   1791     for (i = 0; i < ssi.io_unit_num; i++) {
   1792         io_unit = ssi.io_unit[i];
   1793 
   1794         if (opts->verbose) {
   1795             cli_out("Retrieving packets from unit %d\n", io_unit);
   1796         }
   1797 
   1798         if (sal_sem_take(ssi.lw[io_unit].sema, 
   1799                          soc_property_get(io_unit, 
   1800                                           spn_DIAG_LB_PACKET_TIMEOUT, 
   1801                                           5) * SECOND_USEC)) {
   1802             cli_out("\nTime-out waiting for snake completion on unit %d\n",
   1803                     io_unit);
   1804             cli_out("Receive count is %d; expecting %d pkts.\n\n",
   1805                     ssi.lw[io_unit].rx_pkt_cnt, ssi.num_packets[io_unit]);
   1806             
   1807             SS_UNIT_ITER(sysid, unit) {
   1808                 system_snake_stats(unit, pcfg[unit].port,
   1809                                    ssi.stats[unit]);
   1810                 lbu_snake_dump_stats(unit, pcfg[unit].port,
   1811                                      ssi.stats[unit]);
   1812             }
   1813 
   1814             ssi.lw[io_unit].sema_woke = FALSE;
   1815 
   1816             return (-1);
   1817         }
   1818             
   1819         ssi.lw[io_unit].sema_woke = FALSE;    
   1820         ssi.lw[io_unit].expect_pkts = FALSE; /* Let RX handler ignore pkts */
   1821         
   1822         /* Check counters and packets */
   1823         if (opts->verbose) {
   1824             cli_out("Checking packets received from unit %d\n", io_unit);
   1825         }
   1826 
   1827         if (lbu_snake_analysis(&(ssi.lw[io_unit])) < 0) {
   1828             SS_UNIT_ITER(sysid, unit) {
   1829                 if (system_snake_stats(unit, pcfg[unit].port,
   1830                                        ssi.stats[unit]) < 0) {
   1831                     
   1832                 }
   1833                 lbu_snake_dump_stats(unit, pcfg[unit].port,
   1834                                      ssi.stats[unit]);
   1835             }
   1836             return (-1);
   1837         }
   1838         
   1839         for (ix = 0; ix < ssi.num_packets[io_unit]; ix++) {
   1840             if (ssi.lw[io_unit].tx_pkt_match[ix] == 0) {
   1841                 cli_out("\nTX packet %d did not return to CPU\n", (ix + 1));
   1842             }
   1843         }
   1844     }
   1845      
   1846     /*
   1847      * Do the final stats
   1848      */
   1849     if (opts->verbose) {
   1850         SS_UNIT_ITER(sysid, unit) {
   1851             cli_out("Counters for unit %d (%s)\n", unit, SOC_UNIT_NAME(unit));
   1852             system_snake_stats(unit, pcfg[unit].port, ssi.stats[unit]);
   1853             lbu_snake_dump_stats(unit, pcfg[unit].port, ssi.stats[unit]);
   1854         }
   1855     }
   1856 
   1857     cli_out("Passed\n");
   1858 
   1859     return 0;
   1860 }
   1861 
   1862 STATIC int
   1863 system_snake_done(system_snake_opts_t *opts)
   1864 {
   1865     int                   unit, ix, i, rv;
   1866 
   1867     /* Unregister the callback */
   1868     for (ix = 0; ix < ssi.io_unit_num; ix++) {
   1869         unit = ssi.io_unit[ix];
   1870 
   1871         if (opts->verbose) {
   1872             cli_out("Unregistering Rx callback on unit %d\n", unit);
   1873         }
   1874 
   1875         if ((rv = bcm_rx_unregister(unit, lbu_rx_callback,
   1876                                     BCM_RX_PRIO_MAX)) < 0) {
   1877             cli_out("Failed to unregister RX handler.\n");
   1878         }
   1879 
   1880         if (opts->verbose) {
   1881             cli_out("Stopping Rx on unit %d\n", unit);
   1882         }
   1883 
   1884         if ((rv = bcm_rx_stop(unit, NULL)) < 0) {
   1885             cli_out("system_snake_done: could not stop packet driver: %s\n",
   1886                     bcm_errmsg(rv));
   1887         }
   1888 
   1889         /* Flush out tx packets */
   1890         if (ssi.lw[unit].tx_pkts) {
   1891             bcm_pkt_blk_free(unit, ssi.lw[unit].tx_pkts, 
   1892                              ssi.num_packets[unit]);
   1893             ssi.lw[unit].tx_pkts = NULL;
   1894         }
   1895 
   1896         if (ssi.lw[unit].tx_pkt_match) {
   1897             sal_free(ssi.lw[unit].tx_pkt_match);
   1898             ssi.lw[unit].tx_pkt_match = NULL;
   1899         }
   1900 
   1901         /* Flush out rx packets */
   1902         if (ssi.lw[unit].rx_pkts) {
   1903             for (i = 0; i < ssi.num_packets[unit]; i++) {
   1904                 if (ssi.lw[unit].rx_pkts[i]._pkt_data.data) {
   1905                     bcm_rx_free(unit, ssi.lw[unit].rx_pkts[i]._pkt_data.data);
   1906                 }
   1907             }
   1908             sal_free(ssi.lw[unit].rx_pkts);
   1909             ssi.lw[unit].rx_pkts = NULL;
   1910         }
   1911         
   1912         if (ssi.lw[unit].sema) {
   1913             sal_sem_destroy(ssi.lw[unit].sema);
   1914             ssi.lw[unit].sema = NULL;
   1915         }
   1916 
   1917         if (ssi.stats[unit]) {
   1918             sal_free(ssi.stats[unit]);
   1919             ssi.stats[unit] = NULL;
   1920         }
   1921     }
   1922 
   1923     return 0;
   1924 }
   1925 
   1926 int
   1927 system_snake_test(system_snake_opts_t *opts)
   1928 {
   1929     int           rv, d_rv;
   1930 
   1931     /* Configure system */
   1932     if ((rv = system_snake_init(opts)) < 0) {
   1933         goto cleanup;
   1934     }
   1935 
   1936     /* Transmit packets, wait, check */
   1937     rv = system_snake_run(opts);
   1938 
   1939  cleanup:
   1940     /* Clean up data structures */
   1941     if ((d_rv = system_snake_done(opts)) < 0) {
   1942         return d_rv;
   1943     }
   1944 
   1945     return (rv < 0) ? rv : d_rv;
   1946 }
   1947 
   1948 char cmd_ss_usage[] =
   1949 "ss [Duration=<secs>] [CheckInterval=<secs>]\n\t"
   1950 "   [Mode=MAC|PHY|EXT] [Speed=MAX|10|100|1000|2500|10G]\n\t"
   1951 "Test system with snaked packets.\n\t"
   1952 "This test is supported only for certain platforms.\n\t"
   1953 "HiGig cables must be looped back in pairs.\n\t"
   1954 "Defaults: Duration=10, CheckInterval=5, Mode=PHY, "
   1955     "Speed=DEFAULT(from rc.soc).\n" ;
   1956 
   1957 cmd_result_t
   1958 cmd_ss(int unit, args_t *args)
   1959 {
   1960     system_snake_opts_t opts;
   1961     parse_table_t       pt;
   1962     int                 sysid, rv;
   1963 
   1964     /*
   1965      * Make sure that our current hardware is in the
   1966      * list of platforms that support the ss command.
   1967      */
   1968 
   1969     for (sysid = 0; sysid < SS_SYSID_NUM; sysid++) {
   1970         if (soc_cm_config_var_get(unit, ss_sysid_str[sysid])) {
   1971             break;
   1972         }
   1973     }
   1974 
   1975     if (sysid == SS_SYSID_NUM) {
   1976         cli_out("This test only runs on certain platforms.\n");
   1977         cli_out("One of the following config variables must be\n");
   1978         cli_out("set to indicate the platform:\n");
   1979         for (sysid = 0; sysid < SS_SYSID_NUM; sysid++) {
   1980             cli_out("   %s\n", ss_sysid_str[sysid]);
   1981         }
   1982 
   1983         return CMD_FAIL;
   1984     }
   1985 
   1986     /* cli_out("%s baseboard detected\n",ss_sysid_str[sysid]); */
   1987 
   1988     opts.got_herc = TRUE;
   1989     opts.sysid = sysid;
   1990 
   1991     /* Default values */
   1992     opts.duration = SS_DURATION;
   1993     opts.interval = SS_INTERVAL;
   1994     opts.speed = SS_SPEED_DEFAULT;
   1995     if (sysid ==  SS_SYSID_FIREBOLT) {
   1996         opts.mode = SS_MODE_EXT;
   1997     } else {
   1998         opts.mode = SS_MODE_PHY;
   1999     }
   2000     opts.verbose = FALSE;
   2001     opts.pli = -1;
   2002 
   2003     parse_table_init(unit, &pt);
   2004     parse_table_add(&pt, "Duration", PQ_INT|PQ_DFL, 0,
   2005                     &opts.duration, NULL);
   2006     parse_table_add(&pt, "CheckInterval", PQ_INT|PQ_DFL, 0,
   2007                     &opts.interval, NULL);
   2008     parse_table_add(&pt, "Speed", PQ_MULTI|PQ_DFL, 0,
   2009                     &opts.speed, ss_speed_str);
   2010     parse_table_add(&pt, "Mode", PQ_MULTI|PQ_DFL, 0,
   2011                     &opts.mode, ss_mode_str);
   2012     parse_table_add(&pt, "Verbose", PQ_BOOL|PQ_DFL, 0,
   2013                     &opts.verbose, NULL);
   2014     parse_table_add(&pt, "LengthIncrement", PQ_INT|PQ_DFL, 0,
   2015                     &opts.pli, NULL);
   2016 
   2017     if (parse_arg_eq(args, &pt) < 0) {
   2018         parse_arg_eq_done(&pt);
   2019         return(CMD_USAGE);
   2020     }
   2021 
   2022     if (ARG_CNT(args) > 0) {
   2023         cli_out("%s: Unrecognized extra argument: %s\n",
   2024                 ARG_CMD(args), ARG_CUR(args));
   2025         parse_arg_eq_done(&pt);
   2026         return CMD_USAGE;
   2027     }
   2028 
   2029     parse_arg_eq_done(&pt);
   2030 
   2031     /*
   2032      * Police any cmd line parameters
   2033      */
   2034 
   2035     if (sysid ==  SS_SYSID_FIREBOLT) {
   2036         if (opts.mode != SS_MODE_EXT) {
   2037             cli_out("%s Mode not supported on %s platform. Use tr 39 instead.\n",
   2038                     ss_mode_str[opts.mode], ss_sysid_str[sysid]); 
   2039             return CMD_FAIL;
   2040         }
   2041     }
   2042 
   2043     if (opts.duration < opts.interval) {
   2044         opts.interval = opts.duration;
   2045     }
   2046 
   2047     if (opts.speed == SS_SPEED_MAX) {
   2048         opts.speed = SS_SPEED_DEFAULT;
   2049     }
   2050 
   2051     if (opts.pli > 0) {
   2052         ss_set_packet_length_increment(&opts);
   2053     }
   2054 
   2055     rv = system_snake_test(&opts);
   2056 
   2057     /*
   2058      * Restore current unit since system_snake_test() changes it.
   2059      */
   2060 
   2061     sh_swap_unit_vars(unit);
   2062 
   2063     return rv;
   2064 }
   2065 
   2066 #endif  /* INCLUDE_TEST */
   2067 
   2068 int _diag_system_snake_not_empty;