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

tksdiag.c (95648B)


      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  * File:        tksdiag.c
      8  * Purpose:     CPU transport, CPU DB, and Stacking functions
      9  * Requires:
     10  */
     11 
     12 #include <sal/types.h>
     13 #include <sal/core/libc.h>
     14 #include <sal/core/thread.h>
     15 #include <sal/core/sync.h>
     16 #include <sal/core/dpc.h>
     17 #include <sal/appl/sal.h>
     18 #include <sal/appl/io.h>
     19 #include <shared/bsl.h>
     20 #include <bcm/pkt.h>
     21 #include <bcm/tx.h>
     22 #include <bcm/topo.h>
     23 #include <bcm/init.h>
     24 #include <bcm/stg.h>
     25 #include <bcm/vlan.h>
     26 #include <bcm/stack.h>
     27 #ifdef BCM_RPC_SUPPORT
     28 #include <bcm_int/rpc/rpc.h>
     29 #include <bcm_int/rpc/rlink.h>
     30 #endif /* BCM_RPC_SUPPORT */
     31 #include <bcm_int/control.h>
     32 #include <bcm/debug.h>
     33 
     34 #include <appl/diag/shell.h>
     35 #include <appl/diag/system.h>
     36 #include <appl/diag/parse.h>
     37 #include <appl/diag/ctrans.h>
     38 
     39 #include <appl/cpudb/cpudb.h>
     40 #include <appl/cputrans/cputrans.h>
     41 #include <appl/cputrans/atp.h>
     42 #include <appl/cputrans/next_hop.h>
     43 
     44 #include <appl/discover/disc.h>
     45 #include <appl/stktask/stktask.h>
     46 #include <appl/stktask/topology.h>
     47 #include <appl/stktask/topo_pkt.h>
     48 #include <appl/stktask/topo_brd.h>
     49 #include <appl/stktask/attach.h>
     50 
     51 #if defined(INCLUDE_BOARD)
     52 #include <board/board.h>
     53 #endif
     54 
     55 #include <bcmx/bcmx.h>
     56 
     57 /* Event Logging */
     58 #include <appl/diag/evlog.h>
     59 
     60 #if defined(INCLUDE_SHARED_EVLOG)
     61 #define ST_EVLOG
     62 #endif /* INCLUDE_SHARED_EVLOG */
     63 
     64 
     65 #if defined(BCM_FIELD_SUPPORT) && defined(BCM_FIREBOLT_SUPPORT)
     66 #include <soc/drv.h>    /* For MH Opcode-0 priority workaround */
     67 #endif
     68 
     69 void topo_cpu_dump(topo_cpu_t *topo_cpu, char *prefix);
     70 
     71 
     72 
     73 /* Parsing a CPU KEY is same as parsing a MAC for now */
     74 
     75 #if defined(INCLUDE_LIB_CPUDB) && defined(INCLUDE_LIB_CPUTRANS) && \
     76     defined(INCLUDE_LIB_DISCOVER) && defined(INCLUDE_LIB_STKTASK)
     77 
     78 const bcm_mac_t _bcast_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
     79 
     80 
     81 /****************************************************************
     82  *
     83  * CPUDB control
     84  */
     85 
     86 STATIC INLINE void
     87 db_entry_show(const cpudb_entry_t *entry)
     88 {
     89     const cpudb_stk_port_t  *sp_p;
     90     int                     i;
     91     char                    keybuf[CPUDB_KEY_STRING_LEN];
     92     const cpudb_unit_port_t *sp_base;
     93     char                    pr_buf[80];
     94     cpudb_ref_t             db_ref;
     95     uint32                  flags;
     96     char                    *idstr = "unknown";
     97 
     98     db_ref = entry->db_ref;
     99 
    100     cpudb_key_format(entry->base.key, keybuf, sizeof(keybuf));
    101     cli_out("    Key: %s   MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
    102             keybuf,
    103             entry->base.mac[0], entry->base.mac[1], entry->base.mac[2],
    104             entry->base.mac[3], entry->base.mac[4], entry->base.mac[5]);
    105     cli_out("    Flags 0x%x:%s%s%s%s%s%s%s%s%s%s\n",
    106             entry->flags,
    107             entry->flags & CPUDB_F_IS_MASTER ? " master" : "",
    108             entry->flags & CPUDB_F_IS_LOCAL ? " local" : "",
    109             entry->flags & CPUDB_F_TX_KNOWN ? " tx-known" : "",
    110             entry->flags & CPUDB_F_SYSID_KNOWN ? " sysid-known" : "",
    111             entry->flags & CPUDB_F_DEST_KNOWN ? " dest-known" : "",
    112             entry->flags & CPUDB_F_BASE_INIT_DONE ? " base-init" : "",
    113             entry->flags & CPUDB_F_GLOBAL_COMPLETE ? " gcomp" : "",
    114             entry->flags & CPUDB_F_INACTIVE_MARKED ? " inact" : "",
    115             entry->flags & CPUDB_F_CONFIG_IN ? " cfg in" : "",
    116             entry->flags & CPUDB_F_LOCAL_COMPLETE ? " lcomp" : "");
    117 
    118     /* Base board id and flags */
    119     cpudb_board_idstr_get(entry->base.board_id, &idstr);
    120     cli_out("    Board ID: %d (%s)\n", entry->base.board_id, idstr);
    121     flags = entry->base.flags;
    122     cli_out("        Flags: %08x %s%s%s%s\n", flags,
    123             flags & CPUDB_BASE_F_CHASSIS ? " chassis" : "",
    124             flags & CPUDB_BASE_F_LOAD_BALANCE ? " load-bal" : "",
    125             flags & CPUDB_BASE_F_CHASSIS_AST ? " ast" : "",
    126             flags & CPUDB_BASE_F_CHASSIS_10SLOT ? " 10slot" : "");
    127 
    128     cli_out("    units %d. dest unit %d. base dest port %d. "
    129             "dest mod %d dest port %d.\n",
    130             entry->base.num_units,
    131             entry->base.dest_unit,
    132             entry->base.dest_port,
    133             entry->dest_mod,
    134             entry->dest_port);
    135     for (i = 0; i < entry->base.num_units; i++) {
    136         cli_out("        unit %d: mod id req %d; mod id pref %d\n",
    137                 i, entry->base.mod_ids_req[i], entry->base.pref_mod_id[i]);
    138     }
    139     cli_out("    master prio %d. slot id %d. discovery seq %d.\n",
    140             entry->base.master_pri,
    141             entry->base.slot_id,
    142             entry->base.dseq_num);
    143     cli_out("    dest mod,port %d,%d. tx unit,port %d,%d. num stk %d\n",
    144             entry->dest_mod,
    145             entry->dest_port,
    146             entry->tx_unit,
    147             entry->tx_port,
    148             entry->base.num_stk_ports);
    149     cli_out("    trans pointers %p.\n", (void *)entry->trans_ptr);
    150     for (i = 0; i < entry->base.num_units; i++) {
    151         cli_out("        unit %d: base mod id %d\n", i, entry->mod_ids[i]);
    152     }
    153 
    154     for (i = 0; i < entry->base.num_stk_ports; i++) {
    155         sp_p = &entry->sp_info[i];
    156         sp_base = &entry->base.stk_ports[i];
    157         cli_out("        StkPort %d:  Unit %d. Port %d. "
    158                 "Flags 0x%x:%s%s%s%s%s%s; \n",
    159                 i, sp_base->unit, sp_base->port,
    160                 sp_p->flags,
    161                 sp_p->flags & CPUDB_SPF_NO_LINK ? " nolink" : "",
    162                 sp_p->flags & CPUDB_SPF_INACTIVE ? " inactive" : "",
    163                 sp_p->flags & CPUDB_SPF_DUPLEX ? " duplex" : "",
    164                 sp_p->flags & CPUDB_SPF_CUT_PORT ? " cut_port" : "",
    165                 sp_p->flags & CPUDB_SPF_TX_RESOLVED ? " txok" : "",
    166                 sp_p->flags & CPUDB_SPF_RX_RESOLVED ? " rxok" : "");
    167         cli_out("            Weight %u. Base Flags 0x%x:%s.\n",
    168                 sp_base->weight,
    169                 sp_base->bflags,
    170                 sp_base->bflags & CPUDB_UPF_DISABLE_IF_CUT ? " dis_cut" : "");
    171         cpudb_key_format(sp_p->tx_cpu_key, keybuf, sizeof(keybuf));
    172 
    173         if (CPUDB_KEY_COMPARE(sp_p->tx_cpu_key, sp_p->rx_cpu_key) == 0 &&
    174             sp_p->tx_stk_idx == sp_p->rx_stk_idx) {
    175             sal_sprintf(pr_buf, "TX/RX Key: %s", keybuf);
    176             if (sp_p->tx_stk_idx >= 0) {
    177                 sal_sprintf(pr_buf + strlen(pr_buf), " (rmt-idx %d)",
    178                             sp_p->tx_stk_idx);
    179             }
    180             if (db_ref->local_entry->base.flags & CPUDB_BASE_F_CHASSIS) {
    181                 sal_sprintf(pr_buf + strlen(pr_buf), " to slot %d",
    182                             cpudb_sp_idx_to_slot(db_ref, entry, i, NULL));
    183             }
    184             cli_out("            %s\n", pr_buf);
    185         } else {
    186             if (sp_p->tx_stk_idx >= 0) {
    187                 cli_out("            TX Key: %s (rmt-idx %d)\n",
    188                         keybuf, sp_p->tx_stk_idx);
    189             } else {
    190                 cli_out("            TX Key: %s\n",
    191                         keybuf);
    192             }
    193             cpudb_key_format(sp_p->rx_cpu_key, keybuf, sizeof(keybuf));
    194             if (sp_p->rx_stk_idx >= 0) {
    195                 cli_out("            RX Key: %s (rmt-idx %d)\n",
    196                         keybuf, sp_p->rx_stk_idx);
    197             } else {
    198                 cli_out("            RX Key: %s\n",
    199                         keybuf);
    200             }
    201         }
    202     }
    203 }
    204 
    205 /* Skip to next digit or end of string (0) */
    206 
    207 STATIC char *
    208 _next_digit(char *str)
    209 {
    210     if (str == NULL) {
    211         return str;
    212     }
    213 
    214     while ((*str != 0) && !isdigit((unsigned)*str)) {
    215         str++;
    216     }
    217 
    218     return str;
    219 }
    220 
    221 
    222 /* Parse unit/port pair from string.
    223  * Returns NULL if fails.
    224  * Otherwise, returns updated string pointer
    225  *
    226  * All non-digits are ignored, so the only requirement is that
    227  * the numbers are in pairs.  E.g.:
    228  * "0 1 0 3 0 5"   and    "(0,1) (0,3) (0,5)" are equivalent.
    229  */
    230 
    231 STATIC char *
    232 unit_port_pair_parse(char *str, int *unit, bcm_port_t *port)
    233 {
    234     char *next;
    235     char *orig_str;
    236 
    237     orig_str = str;
    238     str = _next_digit(str);
    239     *unit = strtoul(str, &next, 0);
    240     if (next == str) {
    241         return NULL;
    242     }
    243     str = next;
    244     str = _next_digit(str);
    245     *port = strtoul(str, &next, 0);
    246     if (next == str) {
    247         cli_out("Error parsing unit/port in %s\n", orig_str);
    248         return NULL;
    249     }
    250 
    251     return next;
    252 }
    253 
    254 STATIC INLINE int
    255 port_str_parse(char *str, cpudb_entry_t *entry)
    256 {
    257     char *next;
    258     int i;
    259 
    260     if (str == NULL || *str == 0) {
    261         return 0;
    262     }
    263 
    264     entry->base.num_stk_ports = strtoul(str, &next, 0);
    265     if (next == str) {
    266         return -1;
    267     }
    268 
    269     str = next;
    270     for (i = 0; i < entry->base.num_stk_ports; i++) {
    271         str = unit_port_pair_parse(str, &(entry->base.stk_ports[i].unit),
    272                                    &(entry->base.stk_ports[i].port));
    273 
    274         if (str == NULL) {
    275             return -1;
    276         }
    277     }
    278 
    279     return 0;
    280 }
    281 
    282 STATIC void
    283 db_dump(cpudb_ref_t db_ref)
    284 {
    285     int           i, count;
    286     cpudb_entry_t *entry;
    287     char          keybuf[CPUDB_KEY_STRING_LEN];
    288 
    289     if (cpudb_valid(db_ref)) {
    290         count = cpudb_entry_count_get(db_ref);
    291         cli_out("  DB is valid and contains %d entries\n", count);
    292         if (db_ref->local_entry != NULL) {
    293             cpudb_key_format(db_ref->local_entry->base.key,
    294                              keybuf, sizeof(keybuf));
    295             cli_out("    Local Key: %s\n", keybuf);
    296         }
    297         if (db_ref->master_entry != NULL) {
    298             cpudb_key_format(db_ref->master_entry->base.key,
    299                              keybuf, sizeof(keybuf));
    300             cli_out("    Master Key: %s\n", keybuf);
    301         }
    302         cli_out("\n");
    303         i = 0;
    304         CPUDB_FOREACH_ENTRY(db_ref, entry) {
    305             i += 1;
    306             cli_out("    Entry %d/%d: ", i, count);
    307             db_entry_show(entry);
    308             cli_out("\n");
    309         }
    310         if (i != count) {
    311             cli_out("WARNING: entry count is %d but %d entries actually found\n",
    312                     count, i);
    313         }
    314     } else {
    315         cli_out("DB is not valid\n");
    316     }
    317 }
    318 
    319 #if defined(INCLUDE_BCMX)
    320 /* stktask/bcmx glue */
    321 STATIC void
    322 ct_attach_callback(int unit, int attach, cpudb_entry_t *cpuent, int cpuunit)
    323 {
    324     COMPILER_REFERENCE(cpuent);
    325     COMPILER_REFERENCE(cpuunit);
    326     LOG_VERBOSE(BSL_LS_BCM_STK,
    327                 (BSL_META_U(unit,
    328                             "STACK: Attach callback, unit %d. %s\n"),
    329                  unit, attach ? "attach" : "detach"));
    330     if (attach) {
    331         (void) bcmx_device_attach(unit);
    332     } else {
    333         (void) bcmx_device_detach(unit);
    334     }
    335 }
    336 #endif
    337 
    338 
    339 char ct_cpudb_usage[] =
    340     "cpudb <subcmd> [options]\n"
    341 #ifndef COMPILER_STRING_CONST_LIMIT
    342     "Subcommands:\n"
    343     "    newdb | create\n"
    344     "        Create a new DB and indicate DB reference.  By default, DB 0 is\n"
    345     "        created and used.  Will not change current DB.\n"
    346     "    current <n>\n"
    347     "        Set the current DB reference to <n> (returned from new).\n"
    348     "    destroy | kill <n>\n"
    349     "        Delete the DB indicated\n"
    350     "    update KEY=<key> [MAC=<mac>] [TXUnit=<unit>] [TXPort=<port>]\n"
    351     "            [DMod=<mod>] [DPort=<port>] [ModidsReq=<n>] [MasterPri=<n>]\n"
    352     "            [NumUnits=<n>]\n"
    353     "        Update with the CPU entry with the given key using the\n"
    354     "        information provided.  Negative parameters will be ignored.\n"
    355     "    find | lookup MAC=<mac>\n"
    356     "        Look up the given MAC address\n"
    357     "    show\n"
    358     "        Show contents of the current DB\n"
    359     "    remove KEY=<key>\n"
    360     "        Remove the given KEY\n"
    361     "    stackports PortString=\"<n> <unit0> <port0> ...\" [DBidx=<idx>]\n"
    362     "            Indicate stack ports for the local system; local entry\n"
    363     "            must exist for the given DB\n"
    364     "    add KEY=<key> Local=<T|F>\n"
    365     "        Create an entry in the current DB for the given KEY.\n"
    366     "        Will also add the CPU key to ATP.\n"
    367 #endif
    368     ;
    369 
    370 cpudb_ref_t db_refs[MAX_DBS];
    371 int cur_db;
    372 int num_db = 0;
    373 
    374 cmd_result_t
    375 ct_cpudb(int unit, args_t *args)
    376 {
    377     char *subcmd;
    378     char *int_arg;
    379     parse_table_t pt;
    380     static bcm_mac_t mac;
    381     int a_db;
    382     int tx_port = -1;
    383     int tx_unit = -1;
    384     int dest_mod = -1;
    385     int dest_port = -1;
    386     int master_pri = -1;
    387     int num_units = -1;
    388     cpudb_entry_t *entry;
    389     int slot_id = -1;
    390     int dest_unit = -1;
    391     int i;
    392 #if defined(INCLUDE_BCMX)
    393     static int bcmx_registered = FALSE;
    394 #endif
    395     cpudb_key_t key;
    396 
    397     COMPILER_REFERENCE(unit);
    398 #if defined(INCLUDE_BCMX)
    399     if (!bcmx_registered) {
    400         int rv;
    401         if ((rv = bcm_stack_attach_register(ct_attach_callback)) < 0) {
    402             cli_out("Could not register BCMX with stack attach: %s\n",
    403                     bcm_errmsg(rv));
    404         } else {
    405             bcmx_registered = TRUE;
    406         }
    407     }
    408 #endif
    409     if ((subcmd = ARG_GET(args)) == NULL) {
    410         cli_out("Current DB is %d and is%s valid\n",
    411                 cur_db, cpudb_valid(db_refs[cur_db]) ? "" : " NOT");
    412         return CMD_OK;
    413     }
    414 
    415     if ((sal_strcasecmp(subcmd, "NEWDB") == 0) ||
    416         (sal_strcasecmp(subcmd, "CREATE") == 0)) {
    417         for (i = 0; i < MAX_DBS; i++) {
    418             if (db_refs[i] == NULL) {
    419                 break;
    420             }
    421         }
    422         if (i >= MAX_DBS) {
    423             cli_out("Too many DBs\n");
    424             return CMD_FAIL;
    425         }
    426         if ((db_refs[i] = cpudb_create()) == NULL) {
    427             cli_out("ERROR: cpudb %d create failed\n", i);
    428         } else {
    429             cli_out("cpudb %d created\n", i);
    430             num_db++;
    431         }
    432     } else if (sal_strcasecmp(subcmd, "CURRENT") == 0) {
    433         if ((int_arg = ARG_GET(args)) == NULL) {
    434             cli_out("Current db is %d\n", cur_db);
    435             return CMD_OK;
    436         }
    437         cur_db = strtoul(int_arg, NULL, 0);
    438         cli_out("Current DB set to %d%s\n", cur_db,
    439                 cpudb_valid(db_refs[cur_db]) ? "" :
    440                 " (NOTE:  Not currently valid)");
    441 
    442     } else if ((sal_strcasecmp(subcmd, "KILL") == 0) ||
    443                (sal_strcasecmp(subcmd, "DESTROY") == 0)) {
    444         if ((int_arg = ARG_GET(args)) == NULL) {
    445             cli_out("Destroy requires database refence\n");
    446             return CMD_USAGE;
    447         }
    448         a_db = strtoul(int_arg, NULL, 0);
    449         if (db_refs[a_db] != NULL) {
    450             cli_out("Destroy returns %d\n", cpudb_destroy(db_refs[a_db]));
    451             db_refs[a_db] = NULL;
    452         } else {
    453             cli_out("DB %d does not exist\n", a_db);
    454         }
    455     } else if (sal_strcasecmp(subcmd, "STACKPORTS") == 0) {
    456         int db_idx = cur_db;
    457         char *port_str;
    458 
    459         if (ARG_CUR(args) == NULL) {
    460             cli_out("stack ports required\n");
    461             return CMD_FAIL;
    462         }
    463         parse_table_init(unit, &pt);
    464         parse_table_add(&pt, "PortString", PQ_STRING, 0, &port_str, 0);
    465         parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0);
    466         if (parse_arg_eq(args, &pt) < 0) {
    467             parse_arg_eq_done(&pt);
    468             return CMD_USAGE;
    469         }
    470 
    471         if (db_refs[db_idx] == CPUDB_REF_NULL) {
    472             cli_out("Invalid DB index.  Try cpudb create\n");
    473             parse_arg_eq_done(&pt);
    474             return CMD_FAIL;
    475         }
    476         if (db_refs[db_idx]->local_entry == NULL) {
    477             cli_out("No local DB entry in cpudb %d\n", db_idx);
    478             parse_arg_eq_done(&pt);
    479             return CMD_FAIL;
    480         }
    481         if (port_str_parse(port_str, db_refs[db_idx]->local_entry) < 0) {
    482             cli_out("Bad port string specified: %s\n", port_str);
    483             parse_arg_eq_done(&pt);
    484             return CMD_FAIL;
    485         }
    486         parse_arg_eq_done(&pt);
    487     } else if (sal_strcasecmp(subcmd, "ADD") == 0) {
    488         int  is_local = FALSE;
    489         char keybuf[CPUDB_KEY_STRING_LEN];
    490 
    491         parse_table_init(unit, &pt);
    492         parse_table_add(&pt, "KEY", PQ_DFL|PQ_KEY, 0, key.key, 0);
    493         parse_table_add(&pt, "Local", PQ_DFL|PQ_BOOL, 0, &is_local, 0);
    494         if (parse_arg_eq(args, &pt) < 0) {
    495             parse_arg_eq_done(&pt);
    496             return CMD_USAGE;
    497         }
    498         parse_arg_eq_done(&pt);
    499 
    500         cpudb_key_format(key, keybuf, sizeof(keybuf));
    501         entry = cpudb_entry_create(db_refs[cur_db], key, is_local);
    502         if (entry == NULL) {
    503             cli_out("ERROR: cpudb entry %s create failed\n", keybuf);
    504         } else {
    505             cli_out("cpudb entry %s created\n", keybuf);
    506             atp_key_add(key, is_local);
    507         }
    508     } else if ((sal_strcasecmp(subcmd, "UPDATE") == 0)) {
    509 
    510         parse_table_init(unit, &pt);
    511         sal_memcpy(mac, _bcast_mac, sizeof(bcm_mac_t));
    512 
    513         parse_table_add(&pt, "KEY", PQ_DFL|PQ_KEY, 0, key.key, 0);
    514         parse_table_add(&pt, "MAC", PQ_DFL|PQ_MAC, 0, mac, 0);
    515         parse_table_add(&pt, "TXUnit", PQ_DFL|PQ_INT, 0, &tx_unit, 0);
    516         parse_table_add(&pt, "TXPort", PQ_DFL|PQ_INT, 0, &tx_port, 0);
    517         parse_table_add(&pt, "DMod", PQ_DFL|PQ_INT, 0, &dest_mod, 0);
    518         parse_table_add(&pt, "DPort", PQ_DFL|PQ_INT, 0, &dest_port, 0);
    519         parse_table_add(&pt, "MasterPri", PQ_DFL|PQ_INT, 0, &master_pri, 0);
    520         parse_table_add(&pt, "NumUnits", PQ_DFL|PQ_INT, 0, &num_units, 0);
    521         parse_table_add(&pt, "SlotID", PQ_DFL|PQ_INT, 0, &slot_id, 0);
    522         parse_table_add(&pt, "DestUnit", PQ_DFL|PQ_INT, 0,
    523                         &dest_unit, 0);
    524 
    525         if (parse_arg_eq(args, &pt) < 0) {
    526             parse_arg_eq_done(&pt);
    527             return CMD_USAGE;
    528         }
    529 
    530         CPUDB_KEY_SEARCH(db_refs[cur_db], key, entry);
    531         if (entry == NULL) {
    532             cli_out("Could not find entry for key\n");
    533             parse_arg_eq_done(&pt);
    534             return CMD_FAIL;
    535         }
    536 
    537         if (tx_unit >= 0) {
    538             entry->tx_unit = tx_unit;
    539             entry->flags |= CPUDB_F_TX_KNOWN;
    540         }
    541         if (tx_port >= 0) {
    542             entry->tx_port = tx_port;
    543         }
    544         if (dest_mod >= 0) {
    545             entry->dest_mod = dest_mod;
    546             entry->flags |= CPUDB_F_DEST_KNOWN;
    547         }
    548         if (dest_port >= 0) {  /* For now, set both base and entry port */
    549             entry->base.dest_port = dest_port;
    550             entry->dest_port = dest_port;
    551         }
    552         if (num_units >= 0) {
    553             entry->base.num_units = num_units;
    554         }
    555         if (dest_unit >= 0) {
    556             entry->base.dest_unit = dest_unit;
    557         }
    558         if (slot_id >= 0) {
    559             entry->base.slot_id = slot_id;
    560         }
    561         if (sal_memcmp(mac, _bcast_mac, sizeof(bcm_mac_t))) {
    562             entry->flags |= CPUDB_F_BASE_INIT_DONE;
    563             sal_memcpy(entry->base.mac, mac, sizeof(bcm_mac_t));
    564         }
    565 
    566         if ((tx_unit >= 0 && tx_port < 0) || (tx_port >= 0 && tx_unit < 0)) {
    567             cli_out("Warning:  Not properly initializing tx_unit (%d) and "
    568                     "tx_port (%d)\n", tx_unit, tx_port);
    569         }
    570         if ((dest_mod >= 0 && dest_port < 0) ||
    571             (dest_port >= 0 && dest_mod < 0)) {
    572             cli_out("Warning:  Not properly initializing dest_mode (%d) and "
    573                     "dest_port (%d)\n", dest_mod, dest_port);
    574         }
    575 
    576         parse_arg_eq_done(&pt);
    577     } else if ((sal_strcasecmp(subcmd, "LOOKUP") == 0) ||
    578                (sal_strcasecmp(subcmd, "FIND") == 0)) {
    579         const cpudb_entry_t *entry;
    580 
    581         parse_table_init(unit, &pt);
    582         parse_table_add(&pt, "MAC", PQ_DFL|PQ_MAC, 0, mac, 0);
    583         if (parse_arg_eq(args, &pt) < 0) {
    584             parse_arg_eq_done(&pt);
    585             return CMD_USAGE;
    586         }
    587         parse_arg_eq_done(&pt);
    588 
    589         if ((entry = cpudb_mac_lookup(db_refs[cur_db], mac)) != NULL) {
    590             db_entry_show(entry);
    591         } else {
    592             cli_out("Entry not found in database %d\n", cur_db);
    593         }
    594 
    595     } else if (sal_strcasecmp(subcmd, "SHOW") == 0) {
    596         int valid;
    597         int db_idx;
    598 
    599         cli_out("Current DB index is %d and is%s valid\n", cur_db,
    600                 cpudb_valid(db_refs[cur_db]) ? "" : " NOT");
    601         for (db_idx = 0; db_idx < MAX_DBS; db_idx++) {
    602             valid = cpudb_valid(db_refs[db_idx]);
    603             if (valid) {
    604                 cli_out("\nDB index %d:\n", db_idx);
    605                 db_dump(db_refs[db_idx]);
    606             }
    607         }
    608     } else if (sal_strcasecmp(subcmd, "REMOVE") == 0) {
    609         parse_table_init(unit, &pt);
    610         parse_table_add(&pt, "KEY", PQ_DFL|PQ_KEY, 0, key.key, 0);
    611         if (parse_arg_eq(args, &pt) < 0) {
    612             parse_arg_eq_done(&pt);
    613             return CMD_USAGE;
    614         }
    615         parse_arg_eq_done(&pt);
    616         cli_out("Remove returns %d\n",
    617                 cpudb_entry_remove(db_refs[cur_db], key));
    618     } else if (sal_strcasecmp(subcmd, "UNREGISTER") == 0) {
    619 #if defined(INCLUDE_BCMX)
    620         if (bcmx_registered) {
    621             int rv;
    622 
    623             if ((rv = bcm_stack_attach_unregister(ct_attach_callback)) < 0) {
    624                 cli_out("Could not unregister BCMX with stack attach: %s\n",
    625                         bcm_errmsg(rv));
    626             } else {
    627                 cli_out("cpudb BCMX callback unregistered\n");
    628                 bcmx_registered = FALSE;
    629             }
    630         }
    631 #else
    632         cli_out("cpudb: BCMX is not enabled\n");
    633 #endif
    634     } else {
    635         cli_out("Subcommand not found: %s\n", subcmd);
    636         return CMD_USAGE;
    637     }
    638 
    639     return CMD_OK;
    640 }
    641 
    642 #if 0  
    643 /****************************************************************
    644  *
    645  * TOPOLOGY callbacks
    646  */
    647 
    648 static topo_cpu_t *tp_cpu;
    649 
    650 #define TP_CPU_INIT \
    651     if (tp_cpu == NULL) { \
    652         tp_cpu = sal_alloc(sizeof(*tp_cpu), "tp_cpu"); \
    653         sal_memset(tp_cpu, 0, sizeof(*tp_cpu)); \
    654     }
    655 
    656 #endif  
    657 
    658 /****************************************************************
    659  *
    660  * StackTask thread
    661  */
    662 
    663 /*
    664  * Stack update callback function
    665  *
    666  * This function is registered with stk_port_set as a callback.
    667  * Currently, it interprets the cookie as the COS on which
    668  * stack (next hop) traffic flows and sets up the protocol priority
    669  * on enabled, SL stack ports according to that value.
    670  */
    671 
    672 STATIC void
    673 _stk_port_update(int unit, bcm_port_t port, uint32 flags, void *cookie)
    674 {
    675     int stk_cos;
    676     int rv;
    677 
    678     if (flags & BCM_STK_ENABLE) {
    679         if (flags & BCM_STK_SL) {
    680             stk_cos = PTR_TO_INT(cookie);
    681             LOG_VERBOSE(BSL_LS_BCM_STK,
    682                         (BSL_META_U(unit,
    683                                     "STACK: port update: unit %d, port %d, flags 0x%x,"
    684                                     "stk_cos %d\n"),
    685                          unit, port, flags, stk_cos));
    686 
    687             rv = bcm_switch_control_port_set(unit, port,
    688                                              bcmSwitchCpuProtocolPrio,
    689                                              stk_cos);
    690             if ((rv < 0) && (rv != BCM_E_UNAVAIL)) {
    691                 cli_out("STACK: Error setting CPU protocol priority"
    692                         " on unit %d, port %d: %s\n", unit, port,
    693                         bcm_errmsg(rv));
    694             }
    695         }
    696     } else {
    697         /* Do any special processing needed for a port which is
    698          * removed from stacking.
    699          */
    700     }
    701 }
    702 
    703 
    704 /*
    705  * Workaround for MH Opcode 0 Priority issue on devices,
    706  *     5650x A0, A1
    707  *     5630x A0, B0
    708  *     5610x A0
    709  */
    710 
    711 #define MH_OPCODE0_INIT    0
    712 #define MH_OPCODE0_SELECT  1
    713 #define MH_OPCODE0_CLEAR   2
    714 
    715 #if defined(BCM_FIELD_SUPPORT) && defined(BCM_FIREBOLT_SUPPORT)
    716 /*
    717  * Function:
    718  *     mh_opcode0_priority_select
    719  * Description:
    720  *     Creates FP rule to redirect incoming HiGig port packets with
    721  *     MH Opcode 0 to the CPU port.  In addition, it clears the 
    722  *     'copy-to-cpu' in the icontrol_opcode_bitmap registers for the HiGig.
    723  *     
    724  * Parameters:
    725  *     unit           - BCM device number
    726  *     group_priority - Group priority within allowable range 
    727  *                      (see bcm_field_status_get),
    728  *                      or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
    729  *                      priority; each priority value may be used only once
    730  *     group          - (OUT) New FP Group ID 
    731  *     entry          - (OUT) New FP Entry ID
    732  * Returns:
    733  *     BCM_E_NONE     Success
    734  *     BCM_E_XXX      Failure,
    735  *                    - NULL pointers
    736  *                    - FP subsystem is not initialized
    737  *                    - No more FP resources available
    738  * Notes:
    739  *     FP subsystem must be initialized.
    740  *     This routine should only be executed on (local)
    741  *         5650x A0, A1
    742  *         5630x A0, B0
    743  *         5610x A0
    744  */
    745 
    746 STATIC int
    747 mh_opcode0_priority_select(int unit, 
    748                            int group_priority,
    749                            bcm_field_group_t *group,
    750                            bcm_field_entry_t *entry,
    751                            int               *obm_reg_changed)
    752 {
    753     int                 valid_rev = FALSE;
    754     bcm_port_t          port;
    755     uint32              obm_reg;
    756     bcm_field_qset_t    qset;
    757     uint8               opcode;
    758     uint8               opcode_mask;
    759     uint32              action_param0;
    760     bcm_pbmp_t          in_ports;
    761     bcm_pbmp_t          in_ports_mask;
    762     uint16              dev_id;
    763     uint8               rev_id;
    764 
    765 
    766     /* Check device type and revision */
    767     if ((!SOC_UNIT_VALID(unit))) {
    768         return BCM_E_NONE;
    769     }
    770 
    771     /* Need to check the Revision ID of the device, not the driver */
    772     soc_cm_get_id(unit, &dev_id, &rev_id);
    773 
    774     if (SOC_IS_FIREBOLT(unit) &&
    775         ((rev_id == BCM56504_A0_REV_ID) ||
    776          (rev_id == BCM56504_A1_REV_ID))) {
    777         valid_rev = TRUE;
    778     } else if (SOC_IS_HELIX(unit) &&
    779                ((rev_id == BCM56304_A0_REV_ID) ||
    780                 (rev_id == BCM56304_B0_REV_ID))) {
    781         valid_rev = TRUE;
    782     } else if (SOC_IS_FELIX(unit) &&
    783                (rev_id == BCM56107_A0_REV_ID)) {
    784         valid_rev = TRUE;
    785     }
    786     if (!valid_rev) {  /* No error; not for this device */
    787         return BCM_E_NONE;
    788     }
    789 
    790   
    791     /* Valid devide type, revision */
    792 
    793     if ((group == NULL) || (entry == NULL)) {
    794         return BCM_E_PARAM;
    795     }
    796 
    797     /* Set the HG ingress CPU Opcode map to NOT forward to CPU */
    798     PBMP_ST_ITER(unit, port) {
    799         SOC_IF_ERROR_RETURN(READ_ICONTROL_OPCODE_BITMAPr(unit, port,
    800                                                          &obm_reg));
    801         soc_reg_field_set(unit, ICONTROL_OPCODE_BITMAPr, &obm_reg, BITMAPf,
    802                           0x0);
    803         SOC_IF_ERROR_RETURN(WRITE_ICONTROL_OPCODE_BITMAPr(unit, port,
    804                                                           obm_reg));
    805         *obm_reg_changed = TRUE;
    806     }
    807 
    808 
    809     /* Select qualifiers: MHOpcode, Ingress Ports */
    810     BCM_FIELD_QSET_INIT(qset);
    811     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyMHOpcode);
    812     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyInPorts);
    813     
    814     /* Create group */
    815     BCM_IF_ERROR_RETURN(bcm_field_group_create(unit, qset, 
    816                                                group_priority, group));
    817     /* Create entry */
    818     BCM_IF_ERROR_RETURN(bcm_field_entry_create(unit, *group, entry));
    819 
    820     /* Set qualifiers data, mask */
    821     /* MHOpcode */
    822     opcode = BCM_FIELD_MHOPCODE_CONTROL;
    823     opcode_mask = 0x7;   /* Match all bits */
    824     BCM_IF_ERROR_RETURN(bcm_field_qualify_MHOpcode(unit, *entry, 
    825                                                    opcode, opcode_mask));
    826     /* Ingress Ports */
    827     BCM_PBMP_ASSIGN(in_ports, PBMP_ST_ALL(unit));
    828     BCM_PBMP_ASSIGN(in_ports_mask, PBMP_PORT_ALL(unit));
    829     BCM_IF_ERROR_RETURN(bcm_field_qualify_InPorts(unit, *entry, 
    830                                                   in_ports, in_ports_mask));
    831 
    832     /* Set action to redirect to CPU port */
    833     action_param0 = SOC_PBMP_WORD_GET(PBMP_CMIC(unit), 0);
    834     BCM_IF_ERROR_RETURN(bcm_field_action_add(unit, *entry, 
    835                                              bcmFieldActionRedirectPbmp,
    836                                              action_param0, 0));
    837 
    838     return bcm_field_entry_install(unit, *entry);
    839 }
    840 
    841 
    842 /*
    843  * Function:
    844  *     mh_opcode0_priority_clear
    845  * Description:
    846  *     It destroys the FP rule for the given group ID and entry ID.
    847  *     In addition, it sets the 'copy-to-cpu' flag in the icontrol_opcode_bitmap
    848  *      registers for the HiGig.
    849  *
    850  * Parameters:
    851  *     unit           - BCM device number
    852  *     group          - FP Group ID 
    853  *     entry          - FP Entry ID
    854  * Returns:
    855  *     BCM_E_NONE     Success
    856  *     BCM_E_XXX      Failure
    857  * Notes:
    858  *     This routine is used in conjuction with mh_opcode0_priority_select.
    859  *     This should only be called on those units where the 
    860  *     mh_opcode0_priority_select was successfully called.  The FP group 
    861  *     and entry IDs should have been saved earlier and passed in 
    862  *     to this routine.
    863  *     
    864  *     Given the above, the device type and rev will NOT be validated.
    865  */
    866 
    867 STATIC int
    868 mh_opcode0_priority_clear(int unit, 
    869                           bcm_field_group_t group,
    870                           bcm_field_entry_t entry,
    871                           int obm_reg_changed)
    872 {
    873     bcm_port_t          port;
    874     uint32              obm_reg;
    875 
    876     /* Destroy entry */
    877     if (entry != -1) {
    878         BCM_IF_ERROR_RETURN(bcm_field_entry_remove(unit, entry));
    879         BCM_IF_ERROR_RETURN(bcm_field_entry_destroy(unit, entry));
    880     }
    881 
    882     /* Destroy group */
    883     if (group != -1) {
    884         BCM_IF_ERROR_RETURN(bcm_field_group_destroy(unit, group));
    885     }
    886 
    887     /* Set HG ingress CPU Opcode map to COPY to the CPU */
    888     if (obm_reg_changed) {
    889         PBMP_ST_ITER(unit, port) {
    890             SOC_IF_ERROR_RETURN(READ_ICONTROL_OPCODE_BITMAPr(unit, port,
    891                                                              &obm_reg));
    892             soc_reg_field_set(unit, ICONTROL_OPCODE_BITMAPr, &obm_reg, BITMAPf,
    893                               0x10);
    894             SOC_IF_ERROR_RETURN(WRITE_ICONTROL_OPCODE_BITMAPr(unit, port,
    895                                                               obm_reg));
    896         }
    897     }
    898 
    899     return BCM_E_NONE;
    900 }
    901 
    902 typedef struct mh_opcode0_fp_s {
    903     bcm_field_group_t   group;
    904     bcm_field_entry_t   entry;
    905     int                 obm_reg_changed;
    906 } mh_opcode0_fp_t;
    907 
    908 /*
    909  * Function:
    910  *     mh_opcode0_priority
    911  * Description:
    912  *     This routines performs the specified action for the MH Opcode 0
    913  *     priority.
    914  *     
    915  * Parameters:
    916  *     action         - Action to take,
    917  *                        MH_OPCODE0_INIT    Initializes static data; must 
    918  *                                           be called first
    919  *                        MH_OPCODE0_SELECT  Calls 'priority_select'
    920  *                        MH_OPCODE0_CLEAR   Calls 'priority_clear'
    921  * Returns:
    922  *     BCM_E_NONE     Success
    923  *     BCM_E_XXX      Failure
    924  */
    925 
    926 STATIC int
    927 mh_opcode0_priority(int action)
    928 {
    929     int i;
    930     int rv;
    931     static int init = FALSE;
    932     static mh_opcode0_fp_t mh_opcode0_fp[SOC_MAX_NUM_DEVICES];
    933 
    934     if (!init && (action != MH_OPCODE0_INIT)) {
    935         return BCM_E_INIT;
    936     }
    937 
    938     switch (action) {
    939     case MH_OPCODE0_INIT:
    940         for (i = 0; i < (sizeof(mh_opcode0_fp)/sizeof(mh_opcode0_fp_t)); i++) {
    941             mh_opcode0_fp[i].group = -1;
    942             mh_opcode0_fp[i].entry = -1;
    943             mh_opcode0_fp[i].obm_reg_changed = FALSE;
    944         }
    945         init = TRUE;
    946         break;
    947 
    948     case MH_OPCODE0_SELECT:
    949         for (i = 0; i < soc_ndev; i++) {
    950 
    951             rv = mh_opcode0_priority_select(SOC_NDEV_IDX2DEV(i),
    952                                             BCM_FIELD_GROUP_PRIO_ANY,
    953                                             &mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].group,
    954                                             &mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].entry,
    955                                             &mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].obm_reg_changed);
    956             if (BCM_FAILURE(rv)) {
    957                 cli_out("ERROR: Failed to create FP rule to use HiGig packet "
    958                         "priority on unit %d.\n",SOC_NDEV_IDX2DEV(i));
    959                 cli_out("       Stacking may not work properly.\n");
    960                 return rv;
    961             }
    962         }
    963         break;
    964 
    965     case MH_OPCODE0_CLEAR:
    966         /* Destroy created FP rule on units */
    967         for (i = 0; i < soc_ndev; i++) {
    968             mh_opcode0_priority_clear(SOC_NDEV_IDX2DEV(i),
    969                                       mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].group,
    970                                       mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].entry,
    971                                       mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].obm_reg_changed);
    972             mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].group = -1;
    973             mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].entry = -1;
    974             mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].obm_reg_changed = FALSE;
    975         }
    976         break;
    977         
    978     default:
    979         break;
    980     }
    981 
    982     return BCM_E_NONE;
    983 }
    984 
    985 #else 
    986 
    987 STATIC int
    988 mh_opcode0_priority(int action)
    989 {
    990     COMPILER_REFERENCE(action);
    991     return BCM_E_NONE;
    992 }
    993 
    994 #endif  /* BCM_FIELD_SUPPORT && BCM_FIREBOLT_SUPPORT */
    995 
    996 
    997 #define TKS_STK_DEFAULT_THREAD_PRIORITY 100
    998 static int st_pri = TKS_STK_DEFAULT_THREAD_PRIORITY;
    999 static sal_thread_t st_tid = SAL_THREAD_ERROR;
   1000 static sal_sem_t st_done_sem;
   1001 
   1002 #define TOPO_ATP_FLAGS (ATP_F_NEXT_HOP | ATP_F_REASSEM_BUF)
   1003 
   1004 STATIC void
   1005 tks_st_thread(void *cookie)
   1006 {
   1007     bcm_st_config_t *cfg;
   1008     int rv, unit, i;
   1009     sal_usecs_t attach_timeout;
   1010 
   1011     /* The following call is needed as a workaround for
   1012      * the MHOpcode 0 priority issue in FB, HX, and FX devices
   1013      */
   1014     mh_opcode0_priority(MH_OPCODE0_INIT);
   1015     rv = mh_opcode0_priority(MH_OPCODE0_SELECT);
   1016     if (BCM_FAILURE(rv)) {
   1017         mh_opcode0_priority(MH_OPCODE0_CLEAR);
   1018     }
   1019 
   1020     cfg = (bcm_st_config_t *)cookie;
   1021 
   1022     if ((rv=topo_pkt_handle_init(TOPO_ATP_FLAGS)) != BCM_E_NONE) {
   1023         cli_out("WARNING: topo_pkt_handle_init returned %s\n", bcm_errmsg(rv));
   1024     }
   1025 
   1026     if ((rv=bcm_stack_attach_init()) != BCM_E_NONE) {
   1027         cli_out("WARNING: bcm_stack_attach_init returned %s\n", bcm_errmsg(rv));
   1028     }
   1029 
   1030     rv = bcm_st_start(cfg, TRUE);
   1031     cli_out("ST thread exited with value %d (%s)\n", rv, bcm_errmsg(rv));
   1032     st_tid = SAL_THREAD_ERROR;
   1033 
   1034     cli_out("ST: Stopping RPC and rlink\n");
   1035     
   1036     /* Detach all remote units from BCMX */
   1037     for (unit = 0; unit < BCM_CONTROL_MAX; unit++) {
   1038         if (BCM_CONTROL(unit) == NULL) {
   1039             continue;
   1040         }
   1041 #if defined(INCLUDE_BCMX)
   1042         if (BCM_IS_REMOTE(unit)) {
   1043             (void)bcmx_device_detach(unit);
   1044         }
   1045 #endif /* INCLUDE_BCMX */
   1046     }
   1047 
   1048 #define TKS_STK_THREAD_POLL_FRACTION 100
   1049     /* Make sure an attach thread is not running before stopping RPC */
   1050     if (bcm_st_timeout_get(BCM_STS_ATTACH,
   1051                            &attach_timeout) == BCM_E_NONE) {
   1052         /* Wait twice the attach timeout for stktask to stop */
   1053         for (i=0; i<2*TKS_STK_THREAD_POLL_FRACTION; i++) {
   1054             if (!bcm_stack_attach_running()) {
   1055                 break;
   1056             }
   1057             sal_usleep(attach_timeout/TKS_STK_THREAD_POLL_FRACTION);
   1058         }
   1059 
   1060         if (bcm_stack_attach_running()) {
   1061             cli_out("Attach thread failed to signal completion\n");
   1062         }
   1063         
   1064     } else {
   1065         cli_out("Could not get attach timeout\n");
   1066     }
   1067 
   1068 #ifdef BCM_RPC_SUPPORT
   1069     /* Stop RLINK and RPC */
   1070     (void)bcm_rlink_stop();
   1071     (void)bcm_rpc_stop();
   1072 #endif
   1073 
   1074     mh_opcode0_priority(MH_OPCODE0_CLEAR);
   1075     sal_sem_give(st_done_sem);
   1076     sal_thread_exit(rv);
   1077 }
   1078 
   1079 typedef struct {
   1080     int timeout;
   1081     int rv;
   1082 } tks_st_stop_thread_arg_t;
   1083 
   1084 STATIC void
   1085 tks_st_stop_thread(void *cookie)
   1086 {
   1087     tks_st_stop_thread_arg_t *arg = (tks_st_stop_thread_arg_t *)cookie;
   1088 
   1089     arg->rv = bcm_st_stop(arg->timeout);
   1090 
   1091     sal_thread_exit(0);
   1092 }
   1093 
   1094 static int
   1095 null_attach(cpudb_ref_t db_ref)
   1096 {
   1097     int ismaster = db_ref->local_entry == db_ref->master_entry;
   1098     char master[CPUDB_KEY_STRING_LEN];
   1099     char slave[CPUDB_KEY_STRING_LEN];
   1100 
   1101     master[0] = 0;
   1102     slave[0] = 0;
   1103     if (db_ref->master_entry) {
   1104         cpudb_key_format(db_ref->master_entry->base.key,
   1105 			 master, sizeof(master));
   1106     }
   1107     cpudb_key_format(db_ref->local_entry->base.key, slave, sizeof(slave));
   1108     
   1109     if (ismaster) {
   1110 	cli_out("STACK: master on %s (%d cpu%s)\n",
   1111                 master,
   1112                 db_ref->num_cpus, db_ref->num_cpus == 1 ? "" : "s");
   1113     } else {
   1114 	cli_out("STACK: slave on %s (%d cpus, master %s)\n",
   1115                 slave, db_ref->num_cpus, master);
   1116     }
   1117 
   1118     bcm_st_event_send(BCM_STE_ATTACH_SUCCESS);
   1119     return BCM_E_NONE;
   1120 }
   1121 
   1122 
   1123 #if defined(ST_EVLOG)
   1124 
   1125 STATIC int
   1126 evlog_start(void)
   1127 {
   1128     int   args = 4;
   1129     int   entries = 100;
   1130 
   1131     /* Create log of size 100 entries with 4 arguments */
   1132     if (st_log == NULL) {
   1133         if ((st_log = diag_evlog_create(args, entries)) == NULL) {
   1134             return BCM_E_MEMORY;
   1135         }
   1136     }
   1137     
   1138     SHARED_EVLOG_ENABLE_ALL(st_log);
   1139     return BCM_E_NONE;
   1140 }
   1141 
   1142 STATIC int
   1143 evlog_stop(void)
   1144 {
   1145     if (st_log == NULL) {
   1146         cli_out("No event log\n");
   1147     } else {
   1148         diag_evlog_destroy(st_log);
   1149         st_log = NULL;
   1150     }
   1151 
   1152     return BCM_E_NONE;
   1153 }
   1154 
   1155 STATIC int
   1156 evlog_clear(void)
   1157 {
   1158     if (st_log == NULL) {
   1159         cli_out("No event log\n");
   1160     } else {
   1161         evlog_stop();
   1162         evlog_start();
   1163     }
   1164 
   1165     return BCM_E_NONE;
   1166 }
   1167 
   1168 STATIC void
   1169 evlog_show(args_t *args)
   1170 {
   1171     int           i;
   1172     int           count;
   1173     uint32        flags;
   1174     char          *option;
   1175     int           summary = FALSE;
   1176     int           start, end;
   1177     sal_usecs_t   elapsed_t;
   1178     char          *from = NULL;  /* Previous Stack task state */
   1179     char          *to = NULL;    /* New Stack task state */
   1180     char          *event = NULL; /* Event that triggered state transition */
   1181       
   1182     
   1183     if (st_log == NULL) {
   1184         cli_out("No event log\n");
   1185         return;
   1186     }
   1187 
   1188     if ((option = ARG_GET(args)) != NULL) {
   1189         if (parse_cmp("Summary", option, '\0')) {
   1190             summary = TRUE;
   1191         }
   1192     }
   1193        
   1194     /* Disable logging */
   1195     flags = SHARED_EVLOG_ENABLE_GET(st_log);
   1196     SHARED_EVLOG_ENABLE_SET(st_log, 0);
   1197 
   1198     /* Get log count and check for rollover */
   1199     count = SHARED_EVLOG_COUNT(st_log);
   1200     if (st_log->cur_idx < count) {
   1201         count = st_log->max_entries;
   1202     }
   1203 
   1204     cli_out("Stack Task State Change Event Log");
   1205     if (summary) {
   1206         cli_out(" - Summary");
   1207     }
   1208     cli_out("\n");
   1209     cli_out("  Flags :  0x%x\n", flags);
   1210     cli_out("  Count :  %d\n", count);
   1211     cli_out("\n");
   1212     if (count <= 0) {
   1213         SHARED_EVLOG_ENABLE_SET(st_log, flags);    /* Restore flags */
   1214         return;
   1215     }
   1216     
   1217     
   1218     /*
   1219      * Summary:  Display total time elapsed time for each state
   1220      */
   1221     if (summary) {
   1222         cli_out("  Entry       Elapsed Time   Stack Task State    On\n");
   1223         cli_out("  Start End        (usecs)    From  ==> To       Event\n");
   1224         cli_out("  ----------------------------------------------------\n");
   1225 
   1226         /*
   1227          * The display for the summary option assumes the following
   1228          * log sequence for getting the elapsed time between two log entries:
   1229          *   Stack starts         -> start of Stack state
   1230          *   Start of Stack state -> End of Stack state
   1231          */
   1232 
   1233         start = end = -1;
   1234         for (i = 0; i < count; i++) {
   1235             /* Look for start of stack task */
   1236             if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "stack start")
   1237                 == 0) {
   1238                 start = i++;
   1239                 end   = start;
   1240                 /* Look for the start of a state */
   1241                 for (; i < count; i++) {
   1242                     if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "start")) {
   1243                         continue;
   1244                     }
   1245                     end = i;
   1246                     
   1247                     from  = "(Start)";
   1248                     to    = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log,
   1249                                                                   i, 0)];
   1250                     event = "---";
   1251                     break;
   1252                 }
   1253             } else {
   1254             
   1255                 /* Look for the start of a state */
   1256                 if (start < 0) {
   1257                     if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "start")) {
   1258                         continue;
   1259                     }
   1260                     start = i++;
   1261                 }
   1262             
   1263                 /* Look for the end of a state change */
   1264                 if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "end")) {
   1265                     continue;
   1266                 }
   1267                 
   1268                 end   = i;
   1269                 from  = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 0)];
   1270                 to    = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 1)];
   1271                 event = bcm_st_event_strings[SHARED_EVLOG_ARG(st_log, i, 2)];
   1272             }
   1273 
   1274             if (start == end) {
   1275                 continue;
   1276             }
   1277             
   1278             elapsed_t = SHARED_EVLOG_TIMESTAMP(st_log, end) - 
   1279                         SHARED_EVLOG_TIMESTAMP(st_log, start);
   1280             cli_out("   %3d %3d   %12d    %-8s  %-8s  %-15s\n",
   1281                     start, end,
   1282                     elapsed_t,
   1283                     from, to, event);
   1284 
   1285             start = end;
   1286         }
   1287         cli_out("\n");
   1288         
   1289     } else {
   1290         /*
   1291          * Detail:  Display time elapsed time for each state broken into,
   1292          *          1) Start of state to Event notification to transition
   1293          *             to new state
   1294          *          2) Transitition to new state
   1295          */
   1296 
   1297         cli_out("  Entry  Time(usecs)  Description   Stack Task State    "
   1298                 "On\n");
   1299         cli_out("                                     From  ==> To       "
   1300                 "Event\n");
   1301         cli_out("  -------------------------------------------------------"
   1302                 "----\n");
   1303         for (i = 0; i < count; i++) {
   1304             if (SHARED_EVLOG_ARG(st_log, i, 0) == BCM_STS_INVALID) {
   1305                 from = to = event = "---";
   1306             } else {
   1307                 from  = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 0)];
   1308                 to    = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 1)];
   1309                 event = bcm_st_event_strings[SHARED_EVLOG_ARG(st_log, i, 2)];
   1310             }
   1311 
   1312             cli_out("  %3d  %12d   %-11s   %-8s  %-8s  %-15s\n",
   1313                     i,
   1314                     SHARED_EVLOG_TIMESTAMP(st_log, i),
   1315                     SHARED_EVLOG_STR(st_log, i),
   1316                     from, to, event);
   1317         }
   1318         cli_out("\n");
   1319     }
   1320     
   1321     SHARED_EVLOG_ENABLE_SET(st_log, flags);    /* Restore flags */
   1322 
   1323     return;
   1324 }
   1325 #endif /* ST_EVLOG */
   1326 
   1327 /* Multiblock packet allocator */
   1328 
   1329 #define MAX_NUM_BLKS 50
   1330 
   1331 STATIC int
   1332 tks_pkt_alloc(int unit, int num_blks, int length, uint32 flags, bcm_pkt_t **pkt)
   1333 {
   1334     int i;
   1335     int rv;
   1336     int alength;
   1337     bcm_pkt_t *pkta[MAX_NUM_BLKS];
   1338     bcm_pkt_blk_t *blk = NULL;
   1339 
   1340     if ((num_blks <= 0) || (num_blks >= MAX_NUM_BLKS)) {
   1341         return BCM_E_PARAM;
   1342     }
   1343 
   1344     if (num_blks > 1) {
   1345         blk = sal_alloc(num_blks * sizeof(bcm_pkt_blk_t), "tks_pkt_alloc");
   1346     }
   1347 
   1348     alength = length/num_blks;
   1349 
   1350     for (i=0; i<num_blks; i++) {
   1351 
   1352         /* calculate length needed */
   1353         if (num_blks != 1 && i <= num_blks-2) {
   1354             /* not the last block, so use alength for allocation, and
   1355              subtract from length, so lenggth will be how much is
   1356              needed for the final allocation. */
   1357             length = length - alength;
   1358         } else {
   1359             /* last block, which could also be the first and only block */
   1360             alength = length;
   1361         }
   1362 
   1363         /* Get a pkt */
   1364         rv = bcm_pkt_alloc(unit, alength, flags, &pkta[i]);
   1365 
   1366         if (i == 0) {
   1367             if (num_blks > 1) {
   1368                 blk[i] = *pkta[i]->pkt_data;
   1369                 pkta[i]->pkt_data = blk;
   1370             }
   1371         } else {
   1372             /* not the first packet */
   1373             
   1374             /* Accumulate data segments into first packet */
   1375             pkta[0]->pkt_data[i] = pkta[i]->pkt_data[0];
   1376             pkta[0]->blk_count += 1;
   1377 
   1378             /* Just needed the packet for its data */
   1379             pkta[i]->blk_count -= 1;
   1380             rv = bcm_pkt_free(unit, pkta[i]);
   1381             if (BCM_FAILURE(rv)) {
   1382                 return rv;
   1383             }
   1384         }
   1385     }
   1386 
   1387     *pkt = pkta[0];
   1388 
   1389     return BCM_E_NONE;
   1390 }
   1391 
   1392 STATIC int
   1393 tks_pkt_free(int unit, bcm_pkt_t *pkt)
   1394 {
   1395     int rv, num_blks;
   1396     bcm_pkt_blk_t    *blk;
   1397 
   1398     num_blks = pkt->blk_count;
   1399     blk = pkt->pkt_data;
   1400     rv = bcm_pkt_free(unit, pkt);
   1401     if (num_blks > 1) {
   1402         sal_free(blk);
   1403     }
   1404     return rv;
   1405 }
   1406 
   1407 STATIC void
   1408 tks_list_callback(int unit, bcm_pkt_t *pkt, void *cookie)
   1409 {
   1410     bcm_pkt_t *next;
   1411     int rv;
   1412 
   1413     cli_out("tks_list_callback(%d,%p,%p)\n",unit,(void *)pkt,cookie);
   1414     while(pkt) {
   1415         next = pkt->next;
   1416         rv = tks_pkt_free(pkt->unit, pkt);
   1417         if (BCM_FAILURE(rv)) {
   1418             cli_out("tks_list_callback: tks_pkt_free()=%d\n",rv);
   1419         }
   1420         pkt = next;
   1421     }
   1422 }
   1423 
   1424 STATIC void
   1425 tks_array_callback(int unit, bcm_pkt_t *pkt, void *cookie)
   1426 {
   1427     tks_list_callback(unit,pkt, (void *)3);
   1428     sal_free(cookie);
   1429 }
   1430 
   1431 STATIC void
   1432 tks_pkt_callback(int unit, bcm_pkt_t *pkt, void *cookie)
   1433 {
   1434     int rv;
   1435     sal_vaddr_t ctl = PTR_TO_UINTPTR(cookie);
   1436     void *pktp = (void *)pkt;
   1437 
   1438     if (ctl == 1) {
   1439         rv = tks_pkt_free(unit, pkt);
   1440         /* Coverity will complain if 'pkt' is printed because a function
   1441            is passed a de-allocated resource */
   1442         cli_out("tks_pkt_callback(%d,%p,%p)=%d\n",unit,pktp,cookie,rv);
   1443     } else {
   1444         cli_out("tks_pkt_callback [list]\n");
   1445     }
   1446 }
   1447 
   1448 static bcm_st_config_t st_cfg = {
   1449     disc_start,
   1450     disc_abort,
   1451     NULL,              /* Use default master election routine */
   1452 
   1453     NULL,              /* Use default topology update function */
   1454     NULL,              /* Use default attach update function */
   1455     NULL,              /* Use default transition notify function */
   1456 
   1457     /* Base is filled in from current db */
   1458     {{{0}}},
   1459 };
   1460 
   1461 static char *event_list[] = { EVENT_LIST_NAMES };
   1462 
   1463 char tks_stk_task_usage[] =
   1464     "StkTask START [RETRX=<n>] [CfgTimeout=<n>] [TimeOut=<n>] [DBidx=<n>]\n"
   1465     "         [COS=<n>] [VLAN=<n>] [DiscFallBack=<T|F>]\n"
   1466 #ifndef COMPILER_STRING_CONST_LIMIT
   1467     "    Start the stack task (if not running).\n"
   1468     "StkTask EVENT Event=<UNBlock | BLock | LINKUP | LINKDOWN | PKT |\n"
   1469     "         DRestart | DSuccess | DFailure | TSuccess | TFailure |\n"
   1470     "         ASuccess | AFailure | TimeOut >\n"
   1471     "    Send the indicated event to the stack task (to be implemented)\n"
   1472     "StkTask UPDATE DBidx=<n> [REStart=<T|F>] [MasterPri=n]\n"
   1473     "    Update the stack task base configuration with that of the\n"
   1474     "    given CPU database\n"
   1475     "StkTask TIMEOUT State=<state> TimeOut=<usec>\n"
   1476     "    Set the timeout for the given state\n"
   1477     "StkTask INIT\n"
   1478     "    Init stack task without starting it\n"
   1479     "StkTask DISC [Version=<n>] [FallBack=<T|F>]\n"
   1480     "    Set or display the current discovery version and fallback setting\n"
   1481     "StkTask STOP\n"
   1482     "    Stop the stack task (if running).\n"
   1483     "StkTask TOPO\n"
   1484     "    Dump the topology database\n"
   1485 #if defined(ST_EVLOG)
   1486     "StkTask EVLOG {CLEAR | SHOW [summary]}\n"
   1487     "    Stack task event logging\n"
   1488 #endif /* ST_EVLOG */
   1489 #endif
   1490     ;
   1491 
   1492 extern bcm_st_state_t st_state;
   1493 extern volatile uint32 st_blocked_events;
   1494 extern volatile uint32 st_pending_events;
   1495 extern volatile sal_usecs_t st_transition_time;
   1496 extern uint32 st_stk_port_flags[CPUDB_CXN_MAX];
   1497 extern sal_usecs_t stk_port_last_event_us[CPUDB_CXN_MAX];
   1498 extern uint32 bcm_st_flags;
   1499 extern int _topo_hw_linkscan;
   1500 
   1501 
   1502 cmd_result_t
   1503 tks_stk_task(int unit, args_t *args)
   1504 {
   1505     parse_table_t pt;
   1506     int rv;
   1507     char *subcmd;
   1508     cpudb_ref_t db_ref;
   1509 
   1510     if ((subcmd = ARG_GET(args)) == NULL) {
   1511         int i;
   1512 
   1513         cli_out("Stack Task thread is%s running, state %s, flags 0x%x\n",
   1514                 st_tid == SAL_THREAD_ERROR ? " not" : "",
   1515                 bcm_st_state_strings[st_state],
   1516                 bcm_st_flags);
   1517         for (i = 0; i < 32; i++) {
   1518             if (bcm_st_flags & (1 << i)) {
   1519                 if (i < BCM_STF_MAX) {
   1520                     cli_out("    %s\n", bcm_st_flags_strings[i]);
   1521                 } else {
   1522                     cli_out("    Unknown flag 0x%x\n", bcm_st_flags & (1 << i));
   1523                 }
   1524             }
   1525         }
   1526         cli_out("ST pending ev 0x%x; blocked 0x%x; last trans %u\n",
   1527                 st_blocked_events, st_pending_events,
   1528                 st_transition_time);
   1529         cli_out("Stk ports with link:\n");
   1530         for (i = 0; i < CPUDB_CXN_MAX; i++) {
   1531             if (st_stk_port_flags[i] != 0) {
   1532                 cli_out("    %d%s: Last event %u. Link %s; Last link %s\n",
   1533                         i, st_stk_port_flags[i] & ST_SPF_DISABLED ?
   1534                         " (disabled)" : "",
   1535                         stk_port_last_event_us[i],
   1536                         st_stk_port_flags[i] & ST_SPF_LINK_UP ?
   1537                         "up" : "down",
   1538                         st_stk_port_flags[i] & ST_SPF_LAST_EVENT_UP ?
   1539                         "up" : "down");
   1540             }
   1541         }
   1542 
   1543         if (st_state == BCM_STS_BLOCKED || st_state == BCM_STS_READY) {
   1544             cpudb_ref_t disc = NULL;
   1545             cpudb_ref_t cur = NULL;
   1546             
   1547             if (!cpudb_valid((disc = bcm_st_discovery_db_get()))) {
   1548                 cli_out("Stack task discovery DB is not valid\n");
   1549             } else {
   1550                 cli_out("Stack task discovery DB:\n");
   1551                 db_dump(disc);
   1552             }
   1553             if (!cpudb_valid((cur = bcm_st_current_db_get()))) {
   1554                 cli_out("Stack task current DB is not valid\n");
   1555             } else {
   1556                 cli_out("Stack task current DB:\n");
   1557                 db_dump(cur);
   1558             }
   1559             (void)cpudb_destroy(disc);
   1560             (void)cpudb_destroy(cur);
   1561         } else {
   1562             cli_out("Disc DB %p; Cur DB %p\n", 
   1563                     (void *)bcm_st_disc_db, (void *)bcm_st_cur_db);
   1564             cli_out("Not dumping DBs due to current state\n");
   1565         }
   1566         return CMD_OK;
   1567     }
   1568 
   1569     if (sal_strcasecmp(subcmd, "START") == 0) {
   1570         static int retrx_us = -1;
   1571         static int cfg_to_us = -1;
   1572         static int timeout_us = -1;
   1573         int disc_vlan = -1;
   1574         int disc_cos = -1;
   1575         int disc_fallback = FALSE;
   1576         int auto_trunk = -1;
   1577         int load_balance = -1;
   1578         char *board_id_str = NULL;
   1579         int reserved_modid = -1;
   1580         int db_idx = cur_db;
   1581         uint32 modid_init = 0;
   1582         bcm_st_config_t *cfg = &st_cfg;
   1583         int i;
   1584         bcm_pbmp_t vports, vports_untag;
   1585         int hw_linkscan = TRUE;
   1586         int topo_dly = -1;
   1587         int topo_master_dly = -1;
   1588         int need_board_handler = TRUE;
   1589 
   1590         if (st_tid != SAL_THREAD_ERROR) {
   1591             cli_out("Stack Task is already running\n");
   1592             return CMD_OK;
   1593         }
   1594 
   1595         parse_table_init(unit, &pt);
   1596         parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0);
   1597         parse_table_add(&pt, "RETRX", PQ_DFL|PQ_INT, 0, &retrx_us, 0);
   1598         parse_table_add(&pt, "TimeOut", PQ_DFL|PQ_INT, 0, &timeout_us, 0);
   1599         parse_table_add(&pt, "CfgTimeout", PQ_DFL|PQ_INT, 0, &cfg_to_us, 0);
   1600         parse_table_add(&pt, "Priority", PQ_DFL|PQ_INT, 0, &st_pri, 0);
   1601         parse_table_add(&pt, "COS", PQ_DFL|PQ_INT, 0, &disc_cos, 0);
   1602         parse_table_add(&pt, "VLAN", PQ_DFL|PQ_INT, 0, &disc_vlan, 0);
   1603         parse_table_add(&pt, "rsvdmodidbmp", PQ_DFL|PQ_INT, 0, &modid_init, 0); 
   1604         parse_table_add(&pt, "AutoTrunk", PQ_DFL|PQ_INT, 0, &auto_trunk, 0);
   1605         parse_table_add(&pt, "ReservedModId", PQ_DFL|PQ_INT, 0,
   1606                         &reserved_modid, 0);
   1607         parse_table_add(&pt, "LoadBalance", PQ_DFL|PQ_INT, 0,
   1608                         &load_balance, 0);
   1609         parse_table_add(&pt, "Board", PQ_DFL|PQ_STRING, 0,
   1610                         &board_id_str, 0);
   1611         parse_table_add(&pt, "DiscFallBack", PQ_DFL|PQ_BOOL, 0,
   1612                         &disc_fallback, 0);
   1613         parse_table_add(&pt, "HWLINKscan", PQ_DFL|PQ_BOOL, 0,
   1614                         &hw_linkscan, 0);
   1615         parse_table_add(&pt, "TopoDelay", PQ_DFL|PQ_INT, 0,
   1616                         &topo_dly, 0);
   1617         parse_table_add(&pt, "TopoMasterDelay", PQ_DFL|PQ_INT, 0,
   1618                         &topo_master_dly, 0);
   1619         
   1620         if (parse_arg_eq(args, &pt) < 0) {
   1621             parse_arg_eq_done(&pt);
   1622             return CMD_USAGE;
   1623         }
   1624         disc_timeout_set(timeout_us, cfg_to_us, retrx_us);
   1625         if (disc_cos >= 0) {
   1626             disc_cos_set(disc_cos);
   1627             rv = bcm_stk_update_callback_register(0, _stk_port_update,
   1628                                                   INT_TO_PTR(disc_cos));
   1629             if (rv < 0) {
   1630                 cli_out("ST: Could not set stack callback: %s\n",
   1631                         bcm_errmsg(rv));
   1632             }
   1633         }
   1634         if (disc_vlan >= 0) {
   1635             disc_vlan_set(disc_vlan);
   1636         }
   1637         if (disc_fallback) {
   1638             disc_fallback_set(TRUE);
   1639         }
   1640 
   1641         if (modid_init != 0) {
   1642             topo_reserved_modid_set(modid_init, TRUE);
   1643         }
   1644 
   1645         /* Do not allow HW linkscan mode to be set by Stack task */
   1646         if (hw_linkscan == 0) {
   1647             _topo_hw_linkscan = 0;
   1648         }
   1649         
   1650         if (auto_trunk >= 0) {
   1651             bcm_board_auto_trunk_set(auto_trunk);
   1652         }
   1653 
   1654         if (reserved_modid >= 0) {
   1655             bcm_st_reserved_modid_enable_set(reserved_modid);
   1656         }
   1657 
   1658         if (topo_dly >= 0) {
   1659             topo_delay_set(topo_dly);
   1660         }
   1661 
   1662         if (topo_master_dly >= 0) {
   1663             topo_master_delay_set(topo_master_dly);
   1664         }
   1665 
   1666         if (!cpudb_valid(db_refs[db_idx]) ||
   1667             db_refs[db_idx]->local_entry == NULL) {
   1668             cfg = NULL;
   1669         } else {
   1670 
   1671             db_ref = db_refs[db_idx];
   1672             disc_vlan_get(&disc_vlan);
   1673             BCM_PBMP_CLEAR(vports_untag);
   1674 
   1675             /* Set application flags */
   1676             if (load_balance > 0) {
   1677                 db_ref->local_entry->base.flags |= CPUDB_BASE_F_LOAD_BALANCE;
   1678             }
   1679             if (load_balance > 1) {
   1680                 db_ref->local_entry->base.flags |= CPUDB_BASE_F_CHASSIS_AST;
   1681             }
   1682 #if defined(INCLUDE_BOARD)
   1683             if (board_name() != NULL) {
   1684                 need_board_handler = FALSE;
   1685             }
   1686 #endif
   1687             if (need_board_handler) {
   1688                 rv = topo_board_register(topo_board_default_board_program,
   1689                                          NULL);
   1690                 if (rv < 0) {
   1691                     cli_out("Could not register board programming\n");
   1692                     return CMD_FAIL;
   1693                 }
   1694             }
   1695 
   1696             if (board_id_str != NULL) {
   1697                 rv = cpudb_board_id_get(board_id_str,
   1698                                         &db_ref->local_entry->base.board_id);
   1699                 if (BCM_FAILURE(rv)) {
   1700                     cli_out("ERROR: Could not find board id for '%s'\n",
   1701                             board_id_str);
   1702                     return CMD_FAIL;
   1703                 } else {
   1704                     /* Initialize board */
   1705                     rv = topo_board_initialize(db_ref);
   1706                     if (BCM_FAILURE(rv)) {
   1707                         cli_out("ERROR: Could not initialize board '%s'\n",
   1708                                 board_id_str);
   1709                         return CMD_FAIL;
   1710                     } else {
   1711                         cli_out("Initialized board %s\n", board_id_str);
   1712                     }
   1713                 }
   1714             } else {
   1715                 cli_out("ERROR: No board id\n");
   1716                 return CMD_FAIL;
   1717             }
   1718             /* Put CPU in VLAN for all devices */
   1719             for (i = 0; i < db_ref->local_entry->base.num_units; i++) {
   1720                 rv = bcm_vlan_create(i, disc_vlan);
   1721                 if (rv < 0 && rv != BCM_E_EXISTS) {
   1722                     cli_out("ERROR: vlan %d create failed: %s\n",
   1723                             disc_vlan, bcm_errmsg(rv));
   1724                     return CMD_FAIL;
   1725                 }
   1726                 BCM_PBMP_CLEAR(vports);
   1727                 BCM_PBMP_PORT_ADD(vports, CMIC_PORT(i)); 
   1728                 rv = bcm_vlan_port_add(i, disc_vlan,
   1729                                        vports, vports_untag);
   1730                 if (rv < 0) {
   1731                     cli_out("ERROR: vlan %d CPU port add unit %d failed: %s\n",
   1732                             disc_vlan, unit, bcm_errmsg(rv));
   1733                     return CMD_FAIL;
   1734                 }
   1735             }
   1736             /*
   1737              * For each local stack port, if SL, set DISABLE_IF_CUT;
   1738              * Set the weight inversely to the speed
   1739              */
   1740             for (i = 0; i < db_ref->local_entry->base.num_stk_ports; i++) {
   1741                 int speed;
   1742                 cpudb_unit_port_t *sp =
   1743                     &db_ref->local_entry->base.stk_ports[i];
   1744                 
   1745                 if (bcm_port_speed_get(sp->unit, sp->port, &speed) < 0) {
   1746                     cli_out("Error getting port speed unit %d, port %d\n",
   1747                             sp->unit, sp->port);
   1748                     return CMD_FAIL;
   1749                 }
   1750                 if (speed > 0) {
   1751                     if (speed < 2500) {  /* Assume SL port */
   1752                         sp->bflags |= CPUDB_UPF_DISABLE_IF_CUT;
   1753                     }
   1754                     sp->weight = 1000000/speed;
   1755                 } else {
   1756                     /* The port speed is less than or equal to zero,
   1757                        so set to the highest weight. */
   1758                     sp->weight = 1000000;
   1759                 }
   1760             }
   1761             sal_memcpy(&st_cfg.base, &db_ref->local_entry->base,
   1762                        sizeof(cpudb_base_t));
   1763         }
   1764 
   1765         if (st_done_sem == NULL) {
   1766 
   1767             st_done_sem = sal_sem_create("STDoneSem", sal_sem_BINARY, 0);
   1768 
   1769             if (st_done_sem == NULL) {
   1770                 cli_out("Could not create semaphore\n");
   1771                 return CMD_FAIL;
   1772             }
   1773             
   1774         }
   1775 
   1776         st_tid = sal_thread_create("bcmSTACK",
   1777                                    SAL_THREAD_STKSZ,
   1778                                    st_pri,
   1779                                    tks_st_thread,
   1780                                    cfg);
   1781 #if defined(ST_EVLOG)
   1782         /* Start event logging for Stack task */
   1783         if (st_log != NULL) {
   1784             evlog_stop();
   1785         }
   1786         rv = evlog_start();
   1787         if (rv < 0) {
   1788             cli_out("Cannot start event logging\n");
   1789         } else {
   1790             SHARED_EVENT_LOG(st_log, "STACK START",
   1791                              BCM_STS_INVALID, BCM_STS_INVALID, 0, 0);
   1792         }
   1793 #endif /* ST_EVLOG */
   1794     
   1795         parse_arg_eq_done(&pt);
   1796 
   1797         return CMD_OK;
   1798     } else if (sal_strcasecmp(subcmd, "UPDATE") == 0) {
   1799         int db_idx = cur_db;
   1800         int restart = FALSE;
   1801         int master_pri = -1;
   1802 
   1803         parse_table_init(unit, &pt);
   1804         parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0);
   1805         parse_table_add(&pt, "REStart", PQ_DFL|PQ_BOOL, 0, &restart, 0);
   1806         parse_table_add(&pt, "MasterPri", PQ_DFL|PQ_INT, 0, &master_pri, 0);
   1807         if (parse_arg_eq(args, &pt) < 0) {
   1808             parse_arg_eq_done(&pt);
   1809             return CMD_USAGE;
   1810         }
   1811         parse_arg_eq_done(&pt);
   1812         if (!cpudb_valid(db_refs[db_idx]) ||
   1813             db_refs[db_idx]->local_entry == NULL) {
   1814             cli_out("Invalid DB index.  Try cpudb create\n");
   1815             return CMD_FAIL;
   1816         }
   1817         
   1818         if (master_pri >= 0) {
   1819             db_refs[db_idx]->local_entry->base.master_pri = master_pri;
   1820         }
   1821         
   1822         rv = bcm_st_base_update(&db_refs[db_idx]->local_entry->base,
   1823                                 restart);
   1824         if (rv < 0) {
   1825             cli_out("ST base update ERROR %d: %s\n", rv, bcm_errmsg(rv));
   1826             return CMD_FAIL;
   1827         }
   1828 
   1829     } else if (sal_strcasecmp(subcmd, "DISC") == 0) {
   1830         int ver = -1;
   1831         int disc_fallback = -1;
   1832         int rv;
   1833 
   1834         if (ARG_CNT(args) == 0) {
   1835             if ((rv = disc_version_get(&ver)) < 0) {
   1836                 cli_out("Failed to get current discovery version: %s\n",
   1837                         bcm_errmsg(rv));
   1838                 return CMD_FAIL;
   1839             } else {
   1840                 cli_out("Current discovery version: %d\n", ver);
   1841             }
   1842             if ((rv = disc_fallback_get(&disc_fallback)) < 0) {
   1843                 cli_out("Failed to get discovery fallback setting: %s\n",
   1844                         bcm_errmsg(rv));
   1845                 return CMD_FAIL;
   1846             } else {
   1847                 cli_out("Fallback is %s\n",
   1848                         disc_fallback ? "enable" : "disable");
   1849             }
   1850             return CMD_OK;
   1851         }
   1852 
   1853         parse_table_init(unit, &pt);
   1854         parse_table_add(&pt, "Version", PQ_DFL|PQ_INT, 0, &ver, 0);
   1855         parse_table_add(&pt, "FallBack", PQ_DFL|PQ_BOOL, 0, &disc_fallback, 0);
   1856         if (parse_arg_eq(args, &pt) < 0) {
   1857             parse_arg_eq_done(&pt);
   1858             return CMD_USAGE;
   1859         }
   1860         parse_arg_eq_done(&pt);
   1861 
   1862         if (ver != -1) {
   1863             if ((rv = disc_version_set(ver)) < 0) {
   1864                 cli_out("Failed to set discovery version %d: %s\n", ver,
   1865                         bcm_errmsg(rv));
   1866                 return CMD_FAIL;
   1867             }
   1868         }
   1869         if (disc_fallback != -1) {
   1870             if ((rv = disc_fallback_set(disc_fallback)) < 0) {
   1871                 cli_out("Failed to %s discovery version fallback: %s\n",
   1872                         disc_fallback ? "enable" : "disable",
   1873                         bcm_errmsg(rv));
   1874                 return CMD_FAIL;
   1875             }
   1876         }     
   1877 
   1878         return CMD_OK;
   1879     } else if (sal_strcasecmp(subcmd, "INIT") == 0) {
   1880         int rv;
   1881         int db_idx = cur_db;
   1882 
   1883         parse_table_init(unit, &pt);
   1884         parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0);
   1885         if (parse_arg_eq(args, &pt) < 0) {
   1886             parse_arg_eq_done(&pt);
   1887             return CMD_USAGE;
   1888         }
   1889         if (!cpudb_valid(db_refs[db_idx]) ||
   1890             db_refs[db_idx]->local_entry == NULL) {
   1891             cli_out("Invalid DB index.  Try cpudb create\n");
   1892             parse_arg_eq_done(&pt);
   1893             return CMD_FAIL;
   1894         }
   1895         db_ref = db_refs[db_idx];
   1896         sal_memcpy(&st_cfg.base, &db_ref->local_entry->base,
   1897                    sizeof(cpudb_base_t));
   1898         rv = bcm_st_config_load(&st_cfg);
   1899         cli_out("bcm_st_config_load returned %d\n", rv);
   1900         parse_arg_eq_done(&pt);
   1901         return CMD_OK;
   1902     } else if (sal_strcasecmp(subcmd, "TOPO") == 0) {
   1903         topo_cpu_t *topo;
   1904 
   1905         if (bcm_board_topo_get(&topo) == BCM_E_NONE && topo != NULL) {
   1906             topo_cpu_dump(topo, "");
   1907         } else {
   1908             sal_printf("No Topology\n");
   1909         }
   1910     } else if (sal_strcasecmp(subcmd, "TIMEOUT") == 0) {
   1911         int state = -1;
   1912         sal_usecs_t timeout = 0;
   1913         int rv;
   1914 
   1915         assert(sizeof (timeout) == sizeof (int));
   1916 
   1917         parse_table_init(unit, &pt);
   1918         parse_table_add(&pt, "State", PQ_DFL|PQ_MULTI, 0, &state,
   1919                         bcm_st_state_strings);
   1920         parse_table_add(&pt, "TimeOut", PQ_DFL|PQ_INT, 0, &timeout, 0);
   1921         if (parse_arg_eq(args, &pt) < 0) {
   1922             parse_arg_eq_done(&pt);
   1923             return CMD_USAGE;
   1924         }
   1925         parse_arg_eq_done(&pt);
   1926         if (state < 0) {
   1927             for (state = BCM_STS_BLOCKED; state < BCM_STS_MAX; state++) {
   1928                 bcm_st_timeout_get((bcm_st_state_t)state, &timeout);
   1929                 cli_out("Timeout for %s is %d\n", bcm_st_state_strings[state],
   1930                         timeout);
   1931             }
   1932             return CMD_OK;
   1933         }
   1934         rv = bcm_st_timeout_set((bcm_st_state_t)state, timeout);
   1935         cli_out("Set timeout for %s to %d; returns %d\n",
   1936                 bcm_st_state_strings[state], timeout, rv);
   1937         return CMD_OK;
   1938     } else if (sal_strcasecmp(subcmd, "STOP") == 0) {
   1939         /* Use stktask attach timeout as a proxy for stop timeouts.
   1940            The should make this work in simulation and real modes. */
   1941         tks_st_stop_thread_arg_t stop_arg;
   1942         sal_thread_t st_stop_tid = SAL_THREAD_ERROR;
   1943         sal_usecs_t attach_timeout; 
   1944         int i;
   1945 
   1946         if (bcm_st_timeout_get(BCM_STS_ATTACH,
   1947                                &attach_timeout) != BCM_E_NONE) {
   1948             cli_out("Could not get attach timeout\n");
   1949             return CMD_FAIL;
   1950         }
   1951 
   1952         stop_arg.timeout = attach_timeout/50;
   1953         stop_arg.rv      = BCM_E_INTERNAL;
   1954 
   1955         if (st_tid == SAL_THREAD_ERROR) {
   1956             cli_out("Stack Task is not running\n");
   1957             return CMD_OK;
   1958         }
   1959         
   1960         st_stop_tid = sal_thread_create("STSTOP",
   1961                                    SAL_THREAD_STKSZ,
   1962                                    st_pri,
   1963                                    tks_st_stop_thread,
   1964                                    (void *)&stop_arg);
   1965 
   1966         if (st_stop_tid == SAL_THREAD_ERROR) {
   1967             cli_out("Could not create stack stop thread\n");
   1968             return CMD_FAIL;
   1969         }
   1970         
   1971         /* Wait for the stack thread to signal completion */
   1972         if (sal_sem_take(st_done_sem, attach_timeout*3) < 0) {
   1973             cli_out("Stack thread failed to signal completion\n");
   1974             return CMD_FAIL;
   1975         } else {
   1976             /* Wait for twice the bcm_st_stop timeout for the stop
   1977                thread to complete */
   1978 
   1979 #define TKS_STOP_THREAD_POLL_FRACTION 10
   1980             
   1981             for ( i=0; i<2*TKS_STOP_THREAD_POLL_FRACTION; i++ ) {
   1982                 if (stop_arg.rv == BCM_E_INTERNAL) {
   1983                     sal_usleep(stop_arg.timeout/TKS_STOP_THREAD_POLL_FRACTION);
   1984                 } else {
   1985                     break;
   1986                 }
   1987             }
   1988         }
   1989 
   1990         if (stop_arg.rv == BCM_E_INTERNAL) {
   1991             cli_out("Stack stop thread failed to signal completion\n");
   1992             return CMD_FAIL;
   1993         }
   1994         
   1995         cli_out("bcm_st_stop returns %d: %s\n",
   1996                 stop_arg.rv, bcm_errmsg(stop_arg.rv));
   1997 
   1998 
   1999     } else if (sal_strcasecmp(subcmd, "EVENT") == 0) {
   2000         bcm_st_event_t event = BCM_STE_DISC_RESTART;
   2001         parse_table_init(unit, &pt);
   2002         parse_table_add(&pt, "Event", PQ_DFL | PQ_MULTI, 0, &event,
   2003                         event_list);
   2004         if (parse_arg_eq(args, &pt) < 0) {
   2005             parse_arg_eq_done(&pt);
   2006             return CMD_USAGE;
   2007         }
   2008         rv = bcm_st_event_send(event);
   2009         if (rv < 0) {
   2010             cli_out("bcm_st_send_event ERROR: %s\n", bcm_errmsg(rv));
   2011         }
   2012         parse_arg_eq_done(&pt);
   2013     } else if (sal_strcasecmp(subcmd, "NOATTACH") == 0) {
   2014         st_cfg.st_attach = null_attach;
   2015 #if defined(INCLUDE_ATPTRANS_SOCKET) && defined(INCLUDE_CHASSIS)
   2016     } else if (sal_strcasecmp(subcmd, "CHASSIS_ATPTRANS_SOCKET") == 0) {
   2017         st_cfg.st_transition = bcm_board_chassis_atptrans_socket_transition;
   2018 #endif
   2019 #if defined(ST_EVLOG)
   2020     } else if (sal_strcasecmp(subcmd, "EVLOG") == 0) {
   2021         if ((subcmd = ARG_GET(args)) == NULL) {
   2022             return CMD_USAGE;
   2023         }
   2024         if (sal_strcasecmp(subcmd, "CLEAR") == 0) {
   2025             evlog_clear();
   2026         } else if (sal_strcasecmp(subcmd, "SHOW") == 0) {
   2027             evlog_show(args);
   2028         }
   2029 #endif /* ST_EVLOG */
   2030     } else if (sal_strcasecmp(subcmd, "TX") == 0) {
   2031         /* params */
   2032         int op = BCM_HG_OPCODE_CPU;
   2033         int blk = 1;
   2034         bcm_pbmp_t dest;
   2035         int dmod = 0;
   2036         int dport = 0;
   2037         int tagged = 1;
   2038         int length = 68;
   2039         int reply=0;
   2040         int async=0; /* 0=sync 1=async per list 2=async per packet*/
   2041         int list=0;
   2042         int array=0;
   2043         int ether=0;
   2044         int crc=1;
   2045         int txunit=-1;
   2046         /* vars */
   2047         uint32 flags = 0;
   2048         bcm_pkt_t *pkt = NULL;
   2049         bcm_pkt_t *cur_pkt = NULL;
   2050         bcm_pkt_t *prev_pkt = NULL;
   2051         bcm_pkt_t **pkt_array = NULL;
   2052         int i;
   2053         uint8 *buf = NULL;
   2054         int packets;
   2055         int cmd_rv = CMD_FAIL;
   2056 
   2057         BCM_PBMP_CLEAR(dest);
   2058         parse_table_init(unit, &pt);
   2059         parse_table_add(&pt, "Op", PQ_DFL|PQ_INT, 0, &op, 0);
   2060         parse_table_add(&pt, "Blk", PQ_DFL|PQ_INT, 0, &blk, 0);
   2061         parse_table_add(&pt, "PortBitMap", PQ_DFL|PQ_PBMP, 0, &dest, 0);
   2062         parse_table_add(&pt, "DMod", PQ_DFL|PQ_INT, 0, &dmod, 0);
   2063         parse_table_add(&pt, "DPort", PQ_DFL|PQ_INT, 0, &dport, 0);
   2064         parse_table_add(&pt, "Tagged", PQ_DFL|PQ_INT, 0, &tagged, 0);
   2065         parse_table_add(&pt, "Length", PQ_DFL|PQ_INT, 0, &length, 0);
   2066         parse_table_add(&pt, "Reply", PQ_DFL|PQ_INT, 0, &reply, 0);
   2067         parse_table_add(&pt, "Async", PQ_DFL|PQ_INT, 0, &async, 0);
   2068         parse_table_add(&pt, "LIst", PQ_DFL|PQ_INT, 0, &list, 0);
   2069         parse_table_add(&pt, "ARray", PQ_DFL|PQ_INT, 0, &array, 0);
   2070         parse_table_add(&pt, "Ether", PQ_DFL|PQ_INT, 0, &ether, 0);
   2071         parse_table_add(&pt, "Crc", PQ_DFL|PQ_INT, 0, &crc, 0);
   2072         parse_table_add(&pt, "TXUnit", PQ_DFL|PQ_INT, 0, &txunit, 0);
   2073 
   2074         if (parse_arg_eq(args, &pt) < 0) {
   2075             parse_arg_eq_done(&pt);
   2076             return CMD_USAGE;
   2077         }
   2078 
   2079         parse_arg_eq_done(&pt);
   2080 
   2081         if (blk < 1) {
   2082             cli_out("blk must be greater than 0\n");
   2083             return CMD_USAGE;
   2084         }
   2085 
   2086         if (ether) {
   2087             flags |= BCM_TX_ETHER;
   2088         }
   2089 
   2090         if (crc) {
   2091             flags |= BCM_TX_CRC_APPEND;
   2092         }
   2093 
   2094         if (tagged) {
   2095             length += 4;
   2096             buf = sal_alloc(length, "sttx");
   2097             if (!buf) {
   2098                 cli_out("no memory\n");
   2099                 goto done;
   2100             }
   2101             for (i=0; i<12; i++) {
   2102                 buf[i] = i;
   2103             }
   2104             buf[12] = 0x81;
   2105             buf[13] = 0x00;
   2106             buf[14] = 0x00;
   2107             buf[15] = 0x01;
   2108             for (i=16; i<length; i++) {
   2109                 buf[i] = i-4;
   2110             }
   2111         } else {
   2112             buf = sal_alloc(length, "sttx");
   2113             if (!buf) {
   2114                 cli_out("no memory\n");
   2115                 cmd_rv = CMD_FAIL;
   2116                 goto done;
   2117             }
   2118             for (i=0; i<length; i++) {
   2119                 buf[i] = i;
   2120             }
   2121         }
   2122 
   2123         if (reply) {
   2124             int tmp;
   2125             /* swap SA/DA */
   2126             if (length < 12) {
   2127                 cli_out("length %d too short\n", length);
   2128                 cmd_rv = CMD_FAIL;
   2129                 goto done;
   2130             }
   2131             for (i=0; i<6; i++) {
   2132                 tmp = buf[i];
   2133                 buf[i] = buf[i+6];
   2134                 buf[i+6] = tmp;
   2135             }
   2136         }
   2137 
   2138         if (array > 0 && list > 0) {
   2139             cli_out("Cannot specify array and list at the same time\n");
   2140             cmd_rv = CMD_FAIL;
   2141             goto done;
   2142         }
   2143 
   2144         packets = array ? array : (list ? list : 1);
   2145 
   2146         if (array) {
   2147             pkt_array = sal_alloc(packets * sizeof(bcm_pkt_t *), "sttx");
   2148         }
   2149 
   2150         if (txunit < 0) {
   2151             txunit = unit;
   2152         }
   2153 
   2154         for (i=0; i < packets; i++) {
   2155             rv = tks_pkt_alloc(txunit, blk, length, flags, &cur_pkt);
   2156             if (BCM_FAILURE(rv)) {
   2157                 cli_out("tks_pkt_alloc: %s %d\n", bcm_errmsg(rv),rv);
   2158                 cmd_rv = CMD_FAIL;
   2159                 goto done;
   2160             }
   2161             cur_pkt->dest_mod = dmod;
   2162             cur_pkt->dest_port = dport;
   2163             cur_pkt->opcode = op;
   2164             BCM_PBMP_ASSIGN(cur_pkt->tx_pbmp, dest);
   2165             if (tagged) {
   2166                 BCM_PBMP_CLEAR(cur_pkt->tx_upbmp);
   2167             } else {
   2168                 cur_pkt->_vtag[0] = 0x81;
   2169                 cur_pkt->_vtag[1] = 0x00;
   2170                 cur_pkt->_vtag[2] = 0x00;
   2171                 cur_pkt->_vtag[3] = 0x01;
   2172                 BCM_PBMP_ASSIGN(cur_pkt->tx_upbmp, dest);
   2173                 BCM_PKT_NO_VTAG_REQUIRE(cur_pkt);
   2174             }
   2175             rv = bcm_pkt_memcpy(cur_pkt, 0, buf, length);
   2176             if (BCM_FAILURE(rv)) {
   2177                 cli_out("bcm_pkt_memcpy: %s %d\n", bcm_errmsg(rv),rv);
   2178                 cmd_rv = CMD_FAIL;
   2179                 goto done;
   2180             }
   2181             if ((array > 0 || list > 0) && async > 1) {
   2182                 /* For tx_list() and async > 1, use per packet callback */
   2183                 cur_pkt->call_back = tks_pkt_callback;
   2184             }
   2185 
   2186             /* Keep linked list for packet free */
   2187             if (pkt == NULL) {
   2188                 pkt = cur_pkt;
   2189             }
   2190             if (prev_pkt != NULL) {
   2191                 prev_pkt->next = cur_pkt;
   2192             }
   2193             prev_pkt = cur_pkt;
   2194 
   2195             if (array) {
   2196                 pkt_array[i] = cur_pkt;
   2197             }
   2198         }
   2199 
   2200         if (async) {
   2201             if (list) {
   2202                 cli_out("async tx list:\n");
   2203                 for (cur_pkt = pkt; cur_pkt; cur_pkt=cur_pkt->next) {
   2204                     cli_out("  %p\n", (void *)cur_pkt);
   2205                 }
   2206                 rv = bcm_tx_list(txunit, pkt, tks_list_callback, (void *)2);
   2207             } else if (array) {
   2208                 cli_out("async tx array:\n");
   2209                 for (i = 0; i < packets; i++) {
   2210                     cli_out("  %p\n", (void *)pkt_array[i]);
   2211                 }
   2212                 rv = bcm_tx_array(txunit, pkt_array, packets,
   2213                                   tks_array_callback, (void *)pkt_array);
   2214                 if (BCM_SUCCESS(rv)) {
   2215                     pkt_array = NULL; /* Freed by callback */
   2216                 }
   2217             } else {
   2218                 cli_out("async tx pkt %p\n", (void *)pkt);
   2219                 pkt->call_back = tks_pkt_callback;
   2220                 rv = bcm_tx(txunit, pkt, (void *)1);
   2221             }
   2222         } else {
   2223             if (list) {
   2224                 rv = bcm_tx_list(txunit, pkt, NULL, NULL);
   2225             } else if (array) {
   2226                 rv = bcm_tx_array(txunit, pkt_array, packets, NULL, NULL);
   2227             } else {
   2228                 rv = bcm_tx(txunit, pkt, NULL);
   2229             }
   2230         }
   2231         if (BCM_FAILURE(rv)) {
   2232             cli_out("bcm tx: %s %d\n", bcm_errmsg(rv),rv);
   2233             cmd_rv = CMD_FAIL;
   2234             goto done;
   2235         }
   2236         if (!async) {
   2237             bcm_pkt_t *next_pkt;
   2238             for (cur_pkt = pkt; cur_pkt != NULL; cur_pkt=next_pkt) {
   2239                 next_pkt = cur_pkt->next;
   2240                 rv = tks_pkt_free(txunit, cur_pkt);
   2241                 if (BCM_FAILURE(rv)) {
   2242                     cli_out("tks_pkt_free: %s %d\n", bcm_errmsg(rv),rv);
   2243                     cmd_rv = CMD_FAIL;
   2244                     goto done;
   2245                 }
   2246             }
   2247         }
   2248         cmd_rv = CMD_OK;
   2249 
   2250     done:
   2251         if (buf) {
   2252             sal_free(buf);
   2253         }
   2254         if (pkt_array) {
   2255             sal_free(pkt_array);
   2256         }
   2257         
   2258         return cmd_rv;
   2259     } else if (sal_strcasecmp(subcmd, "MODPORT") == 0) {
   2260         /* params */
   2261         int modid = 0;
   2262         int dest;
   2263         
   2264         parse_table_init(unit, &pt);
   2265         parse_table_add(&pt, "Modid", PQ_DFL|PQ_INT, 0, &modid, 0);
   2266         parse_table_add(&pt, "Port", PQ_DFL|PQ_INT, 0, &dest, 0);
   2267         if (parse_arg_eq(args, &pt) < 0) {
   2268             parse_arg_eq_done(&pt);
   2269             return CMD_USAGE;
   2270         }
   2271         parse_arg_eq_done(&pt);
   2272         rv = bcm_stk_modport_set(unit, modid, dest);
   2273         if (BCM_FAILURE(rv)) {
   2274             cli_out("bcm_stk_modport_set: %s %d\n", bcm_errmsg(rv),rv);
   2275             return CMD_FAIL;
   2276         }
   2277         return CMD_OK;
   2278     } else if (sal_strcasecmp(subcmd, "MODID") == 0) {
   2279         /* params */
   2280         int modid = 0;
   2281         parse_table_init(unit, &pt);
   2282         parse_table_add(&pt, "Modid", PQ_DFL|PQ_INT, 0, &modid, 0);
   2283         if (parse_arg_eq(args, &pt) < 0) {
   2284             parse_arg_eq_done(&pt);
   2285             return CMD_USAGE;
   2286         }
   2287         parse_arg_eq_done(&pt);
   2288         rv = bcm_stk_my_modid_set(unit, modid);
   2289         if (BCM_FAILURE(rv)) {
   2290             cli_out("bcm_stk_my_modid_set: %s %d\n", bcm_errmsg(rv),rv);
   2291             return CMD_FAIL;
   2292         }
   2293         return CMD_OK;
   2294     } else {
   2295         cli_out("Subcommand not found: %s\n", subcmd);
   2296         return CMD_USAGE;
   2297     }
   2298 
   2299     return CMD_OK;
   2300 }
   2301 
   2302 
   2303 /****************************************************************
   2304  *
   2305  * CPUDB DUMP AND PARSE ROUTINES
   2306  *
   2307  * DB dump and parse routines work in tandem.  After configuration,
   2308  * the current stack task DB can be dumped.  This creates a script
   2309  * (a list of dbparse commands) that can be read in on a different
   2310  * system to recreate the DB and topology information.
   2311  *
   2312  * The parsing is stateful and the order of the dbparse commands
   2313  * is very important.  For example, 'dbparse object=cpudb_stk_port...'
   2314  * gives info about a stack port; but which stack port is implied
   2315  * in the current state of the parsing (what was the last DB
   2316  * entry created and which stack ports were added previously).
   2317  *
   2318  * The DB parse routines will install the data into the current
   2319  * CPU DB (from cpudb create) and into parse_tp_cpu.
   2320  */
   2321 
   2322 static topo_cpu_t *parse_tp_cpu;
   2323 
   2324 #define PARSE_TP_CPU_INIT \
   2325     if (parse_tp_cpu == NULL) { \
   2326         parse_tp_cpu = sal_alloc(sizeof(*parse_tp_cpu), "parse_tp_cpu"); \
   2327         sal_memset(parse_tp_cpu, 0, sizeof(*parse_tp_cpu)); \
   2328     }
   2329 
   2330 /* Dump a CPUDB entry's stack port */
   2331 void
   2332 stk_ports_dump(cpudb_entry_t *entry, char *prefix)
   2333 {
   2334     cpudb_stk_port_t *sp;
   2335     int i;
   2336 
   2337     for (i = 0; i < entry->base.num_stk_ports; i++) {
   2338         sp = &entry->sp_info[i];
   2339         sal_printf("%s object=cpudb_stk_port \\\n"
   2340                    "    weight=0x%x \\\n"
   2341                    "    base_flags=0x%x \\\n"
   2342                    "    flags=0x%x \\\n"
   2343                    "    unit=%d \\\n"
   2344                    "    port=%d \\\n"
   2345                    "    tx_cpu_key=%x:%x:%x:%x:%x:%x \\\n"
   2346                    "    tx_stk_idx=%d \\\n"
   2347                    "    rx_cpu_key=%x:%x:%x:%x:%x:%x \\\n"
   2348                    "    rx_stk_idx=%d\n",
   2349                    prefix,
   2350                    entry->base.stk_ports[i].weight,
   2351                    entry->base.stk_ports[i].bflags,
   2352                    sp->flags,
   2353                    entry->base.stk_ports[i].unit,
   2354                    entry->base.stk_ports[i].port,
   2355                    MAC_ADDR_LIST(sp->tx_cpu_key.key),
   2356                    sp->tx_stk_idx,
   2357                    MAC_ADDR_LIST(sp->rx_cpu_key.key),
   2358                    sp->rx_stk_idx);
   2359     }
   2360 }
   2361 
   2362 /* Dump a CPUDB entry's stack port */
   2363 void
   2364 cpudb_units_dump(cpudb_entry_t *entry, char *prefix)
   2365 {
   2366     int i;
   2367 
   2368     for (i = 0; i < entry->base.num_units; i++) {
   2369         sal_printf("%s object=cpudb_unit_mod_ids \\\n"
   2370                    "    mod_ids_req=%d \\\n"
   2371                    "    pref_mod_id=%d \\\n"
   2372                    "    mod_id=%d\n",
   2373                    prefix,
   2374                    entry->base.mod_ids_req[i],
   2375                    entry->base.pref_mod_id[i],
   2376                    entry->mod_ids[i]);
   2377     }
   2378 }
   2379 
   2380 /* Dump a CPUDB entry */
   2381 
   2382 void
   2383 cpudb_entry_dump(cpudb_entry_t *entry, char *prefix)
   2384 {
   2385     cpudb_base_t *base;
   2386 
   2387     base = &entry->base;
   2388     sal_printf("%s object=cpudb_entry key=%x:%x:%x:%x:%x:%x \\\n"
   2389                "    mac=%x:%x:%x:%x:%x:%x \\\n"
   2390                "    master_pri=%d \\\n"
   2391                "    slot_id=%d \\\n"
   2392                "    dest_unit=%d \\\n"
   2393                "    base_dest_port=%d \\\n"
   2394                "    flags=0x%x \\\n"
   2395                "    tx_unit=%d \\\n"
   2396                "    tx_port=%d \\\n"
   2397                "    dest_mod=%d \\\n"
   2398                "    dest_port=%d \\\n"
   2399                "    topo_idx=%d\n",
   2400                prefix,
   2401                MAC_ADDR_LIST(base->key.key),
   2402                MAC_ADDR_LIST(base->mac),
   2403                base->master_pri,
   2404                base->slot_id,
   2405                base->dest_unit,
   2406                base->dest_port,
   2407                entry->flags,
   2408                entry->tx_unit,
   2409                entry->tx_port,
   2410                entry->dest_mod,
   2411                entry->dest_port,
   2412                entry->topo_idx);
   2413     stk_ports_dump(entry, prefix);
   2414     cpudb_units_dump(entry, prefix);
   2415 }
   2416 
   2417 /* Dump topology mod id lists for a stack port */
   2418 
   2419 void
   2420 topo_stk_port_dump(topo_stk_port_t *sp, char *prefix)
   2421 {
   2422     int i;
   2423 
   2424     sal_printf("%s object=topo_stk_port flags=0x%x\n",
   2425                prefix,
   2426                sp->flags);
   2427     for (i = 0; i < sp->tx_mod_num; i++) {
   2428         sal_printf("%s object=topo_tx_mod mod_id=%d\n",
   2429                    prefix,
   2430                    sp->tx_mods[i]);
   2431     }
   2432     for (i = 0; i < sp->rx_mod_num; i++) {
   2433         sal_printf("%s object=topo_rx_mod mod_id=%d\n",
   2434                    prefix,
   2435                    sp->rx_mods[i]);
   2436     }
   2437 }
   2438 
   2439 /* Dump a topology CPU structure */
   2440 
   2441 void
   2442 topo_cpu_dump(topo_cpu_t *topo_cpu, char *prefix)
   2443 {
   2444     int i;
   2445 
   2446     sal_printf("%s object=topo_cpu \\\n", prefix);
   2447     sal_printf("    key=%x:%x:%x:%x:%x:%x \\\n",
   2448                MAC_ADDR_LIST(topo_cpu->local_entry.base.key.key));
   2449     sal_printf("    version=%d \\\n"
   2450                "    master_seq_num=%d \\\n"
   2451                "    flags=0x%x\n",
   2452                topo_cpu->version,
   2453                topo_cpu->master_seq_num,
   2454                topo_cpu->flags);
   2455     for (i = 0; i < topo_cpu->local_entry.base.num_stk_ports; i++) {
   2456         topo_stk_port_dump(&(topo_cpu->tp_stk_port[i]), prefix);
   2457     }
   2458     sal_printf("\n# End of topology dump.\n\n");
   2459 }
   2460 
   2461 /* Dump a CPUDB including topology info */
   2462 
   2463 void
   2464 cpudb_dump(cpudb_ref_t db, char *prefix)
   2465 {
   2466     cpudb_entry_t *entry;
   2467 
   2468     if (!cpudb_valid(db)) {
   2469         cli_out("DB is not valid\n");
   2470         return;
   2471     }
   2472 
   2473     sal_printf("# Dump CPU DB\n");
   2474     sal_printf("# WARNING:  DB parsing is stateful and order specific.\n");
   2475     sal_printf("# WARNING:  Changing the order of dbparse commands\n");
   2476     sal_printf("# WARNING:  will change or break the resulting parse\n\n");
   2477     CPUDB_FOREACH_ENTRY(db, entry) {
   2478         cpudb_entry_dump(entry, prefix);
   2479     }
   2480 
   2481     if (db->master_entry != NULL) {
   2482         sal_printf("%s object=master_key key=%x:%x:%x:%x:%x:%x\n",
   2483                    prefix,
   2484                    MAC_ADDR_LIST(db->master_entry->base.key.key));
   2485     }
   2486 
   2487     if (db->local_entry != NULL) {
   2488         sal_printf("%s object=local_key key=%x:%x:%x:%x:%x:%x\n",
   2489                    prefix,
   2490                    MAC_ADDR_LIST(db->local_entry->base.key.key));
   2491     }
   2492     sal_printf("\n# End of CPUDB dump.\n");
   2493 }
   2494 
   2495 char cmd_st_db_dump_usage[] =
   2496     "Dump the current stack task CPUDB in a parsable format\n";
   2497 
   2498 cmd_result_t
   2499 cmd_st_db_dump(int ignored_unit, args_t *args)
   2500 {
   2501     if (!cpudb_valid(bcm_st_cur_db)) {
   2502         cli_out("Stack task current DB is not valid\n");
   2503         return CMD_OK;
   2504     }
   2505 
   2506     sal_printf("\n# Dumping current stack task CPUDB\n\n");
   2507     cpudb_dump(bcm_st_cur_db, "dbparse");
   2508     sal_printf("\n\n# Clear topology info before parsing\n");
   2509     sal_printf("dbparse object=topo_clear\n");
   2510 
   2511     return CMD_OK;
   2512 }
   2513 
   2514 static char *parse_object_list[] = { PARSE_OBJECT_NAMES };
   2515 
   2516 char cmd_cpudb_parse_usage[] =
   2517     "Parse a CPUDB object command generated by CPUDB dump\n";
   2518 
   2519 static cpudb_key_t current_key;
   2520 static int current_topo_sp_idx;
   2521 
   2522 #define CHECK_SET(dest, val) if ((val) >= 0) (dest) = (val)
   2523 
   2524 /* Add stack port to the given entry */
   2525 STATIC int _stk_port_add(cpudb_entry_t *entry, int unit, bcm_port_t port,
   2526                          int weight, int base_flags,
   2527                          int flags, int tx_stk_idx, int rx_stk_idx,
   2528                          cpudb_key_t tx_cpu_key, cpudb_key_t rx_cpu_key)
   2529 {
   2530     int cur_sp;
   2531     cpudb_stk_port_t *sp;
   2532     
   2533     if (entry->base.num_stk_ports >= CPUDB_STK_PORTS_MAX) {
   2534         cli_out("ERROR: failed to add stack port unit=%d port=%d to cpudb "
   2535                 "(max=%d)\n", unit, port, CPUDB_STK_PORTS_MAX);
   2536         return BCM_E_FAIL;
   2537     }
   2538     
   2539     cur_sp = entry->base.num_stk_ports++;
   2540     entry->base.stk_ports[cur_sp].weight = weight;
   2541     entry->base.stk_ports[cur_sp].bflags = base_flags;
   2542     entry->base.stk_ports[cur_sp].unit = unit;
   2543     entry->base.stk_ports[cur_sp].port = port;
   2544     sp = &entry->sp_info[cur_sp];
   2545     sp->flags = flags;
   2546     CPUDB_KEY_COPY(sp->tx_cpu_key, tx_cpu_key);
   2547     sp->tx_stk_idx = tx_stk_idx;
   2548     CPUDB_KEY_COPY(sp->rx_cpu_key, rx_cpu_key);
   2549     sp->rx_stk_idx = rx_stk_idx;
   2550 
   2551     return BCM_E_NONE;
   2552 }
   2553 
   2554 /*
   2555  * Parse a port specification string of unit, port pairs, adding each
   2556  * as a stack port to the given entry.  See notes at unit_port_pair_parse.
   2557  */
   2558 
   2559 STATIC cmd_result_t
   2560 _port_string_parse(cpudb_entry_t *entry, char *port_str)
   2561 {
   2562     int unit;
   2563     bcm_port_t port;
   2564     static cpudb_key_t empty_key;  /* Initialized to 0 in BSS */
   2565 
   2566     if (port_str == NULL) {
   2567         return CMD_FAIL;
   2568     }
   2569 
   2570     port_str = _next_digit(port_str);
   2571     do {
   2572         port_str = unit_port_pair_parse(port_str, &unit, &port);
   2573         if (port_str != NULL) {
   2574             if (BCM_FAILURE(_stk_port_add(entry, unit, port, 0, 0, 0,
   2575                                           -1, -1, empty_key, empty_key))) {
   2576                 return CMD_FAIL;
   2577             }
   2578             port_str = _next_digit(port_str);
   2579         } else {
   2580             cli_out("Error parsing port string: %s\n", port_str);
   2581         }
   2582     } while ((port_str != NULL) && (*port_str != 0));
   2583 
   2584     return port_str == NULL ? CMD_FAIL : CMD_OK;
   2585 }
   2586 
   2587 /*
   2588  * Requires the notion of a "current DB" (fixed for entire parsing)
   2589  * and "current DB entry" (updated by parsing routine)
   2590  */
   2591 
   2592 cmd_result_t
   2593 cmd_cpudb_parse(int ignored_unit, args_t *args)
   2594 {
   2595     parse_table_t pt;
   2596     int object;
   2597     int base_dest_port = -1,
   2598         dest_mod = -1,
   2599         dest_port = -1,
   2600         dest_unit = -1,
   2601         flags = 0,
   2602         weight = 0,
   2603         base_flags = 0,
   2604         master_pri = -1,
   2605         master_seq_num = -1,
   2606         mod_id = -1,
   2607         mod_ids_req = -1,
   2608         num_stk_ports = -1,
   2609         port = -1,
   2610         pref_mod_id = -1,
   2611         rx_stk_idx = -1,
   2612         slot_id = -1,
   2613         topo_idx = -1,
   2614         tx_port = -1,
   2615         tx_stk_idx = -1,
   2616         tx_unit = -1,
   2617         unit = -1,
   2618         version = -1;
   2619     cpudb_key_t key, rx_cpu_key, tx_cpu_key;
   2620     bcm_mac_t mac;
   2621     cpudb_ref_t db_ref;
   2622     cpudb_entry_t *entry;
   2623     cpudb_base_t *base;
   2624     topo_stk_port_t *topo_sp;
   2625     cmd_result_t cmd_rv = CMD_OK;
   2626     int cur_unit;
   2627     int db_idx = cur_db;
   2628     char *sp_string;
   2629     int rv;
   2630 
   2631     sal_memset(&key, 0, sizeof(cpudb_key_t));
   2632     sal_memset(&rx_cpu_key, 0, sizeof(cpudb_key_t));
   2633     sal_memset(&tx_cpu_key, 0, sizeof(cpudb_key_t));
   2634     sal_memset(mac, 0, sizeof(bcm_mac_t));
   2635 
   2636     parse_table_init(unit, &pt);
   2637     parse_table_add(&pt, "OBJECT", PQ_DFL | PQ_MULTI, 0, &object,
   2638                     parse_object_list);
   2639     parse_table_add(&pt, "DB_IDX", PQ_DFL | PQ_INT, 0, &db_idx, 0);
   2640     parse_table_add(&pt, "BASE_DEST_PORT", PQ_DFL | PQ_INT, 0, &base_dest_port, 0);
   2641     parse_table_add(&pt, "BASE_FLAGS", PQ_DFL | PQ_INT, 0, &base_flags, 0);
   2642     parse_table_add(&pt, "DEST_MOD", PQ_DFL | PQ_INT, 0, &dest_mod, 0);
   2643     parse_table_add(&pt, "DEST_PORT", PQ_DFL | PQ_INT, 0, &dest_port, 0);
   2644     parse_table_add(&pt, "DEST_UNIT", PQ_DFL | PQ_INT, 0, &dest_unit, 0);
   2645     parse_table_add(&pt, "FLAGS", PQ_DFL | PQ_INT, 0, &flags, 0);
   2646     parse_table_add(&pt, "KEY", PQ_DFL | PQ_KEY, 0, key.key, 0);
   2647     parse_table_add(&pt, "MAC", PQ_DFL | PQ_MAC, 0, mac, 0);
   2648     parse_table_add(&pt, "MASTER_PRI", PQ_DFL | PQ_INT, 0, &master_pri, 0);
   2649     parse_table_add(&pt, "MASTER_SEQ_NUM", PQ_DFL | PQ_INT, 0, &master_seq_num, 0);
   2650     parse_table_add(&pt, "MOD_ID", PQ_DFL | PQ_INT, 0, &mod_id, 0);
   2651     parse_table_add(&pt, "MOD_IDS_REQ", PQ_DFL | PQ_INT, 0, &mod_ids_req, 0);
   2652     parse_table_add(&pt, "NUM_STK_PORTS", PQ_DFL | PQ_INT, 0, &num_stk_ports, 0);
   2653     parse_table_add(&pt, "PORT", PQ_DFL | PQ_INT, 0, &port, 0);
   2654     parse_table_add(&pt, "PREF_MOD_ID", PQ_DFL | PQ_INT, 0, &pref_mod_id, 0);
   2655     parse_table_add(&pt, "RX_CPU_KEY", PQ_DFL | PQ_KEY, 0, rx_cpu_key.key, 0);
   2656     parse_table_add(&pt, "RX_STK_IDX", PQ_DFL | PQ_INT, 0, &rx_stk_idx, 0);
   2657     parse_table_add(&pt, "SLOT_ID", PQ_DFL | PQ_INT, 0, &slot_id, 0);
   2658     parse_table_add(&pt, "SP_STRING", PQ_STRING, 0, &sp_string, 0);
   2659     parse_table_add(&pt, "TOPO_IDX", PQ_DFL | PQ_INT, 0, &topo_idx, 0);
   2660     parse_table_add(&pt, "TX_CPU_KEY", PQ_DFL | PQ_KEY, 0, tx_cpu_key.key, 0);
   2661     parse_table_add(&pt, "TX_PORT", PQ_DFL | PQ_INT, 0, &tx_port, 0);
   2662     parse_table_add(&pt, "TX_STK_IDX", PQ_DFL | PQ_INT, 0, &tx_stk_idx, 0);
   2663     parse_table_add(&pt, "TX_UNIT", PQ_DFL | PQ_INT, 0, &tx_unit, 0);
   2664     parse_table_add(&pt, "UNIT", PQ_DFL | PQ_INT, 0, &unit, 0);
   2665     parse_table_add(&pt, "VERSION", PQ_DFL | PQ_INT, 0, &version, 0);
   2666     parse_table_add(&pt, "WEIGHT", PQ_DFL | PQ_INT, 0, &weight, 0);
   2667 
   2668     if (parse_arg_eq(args, &pt) < 0) {
   2669         parse_arg_eq_done(&pt);
   2670         return CMD_USAGE;
   2671     }
   2672 
   2673     if (db_idx < 0 || db_idx >= MAX_DBS) {
   2674         parse_arg_eq_done(&pt);
   2675         sal_printf("Bad db index %d\n", db_idx);
   2676         return CMD_USAGE;
   2677     }
   2678     db_ref = db_refs[db_idx];
   2679     if (!cpudb_valid(db_ref)) {
   2680         parse_arg_eq_done(&pt);
   2681         sal_printf("DB reference %d is not valid\n", db_idx);
   2682         return CMD_USAGE;
   2683     }
   2684 
   2685     switch (object) {
   2686     case PARSE_OBJ_CPUDB_ENTRY    :  /* Sets current key */
   2687         CPUDB_KEY_SEARCH(db_ref, key, entry);
   2688         if (entry != NULL) {
   2689             sal_printf("CPUDB PARSE ENTRY:  WARNING key already in DB "
   2690                        CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key));
   2691         }
   2692         CPUDB_KEY_COPY(current_key, key);
   2693         entry = cpudb_entry_create(db_ref, key, FALSE);
   2694         if (entry == NULL) {
   2695             sal_printf("CPUDB PARSE ENTRY:  ERROR failed to create entry for "
   2696                        CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key));
   2697             cmd_rv = CMD_FAIL;
   2698             break;
   2699         }
   2700         base = &entry->base;
   2701         sal_memcpy(entry->base.mac, mac, sizeof(bcm_mac_t));
   2702 
   2703         CHECK_SET(entry->flags, flags);
   2704         CHECK_SET(base->master_pri, master_pri);
   2705         CHECK_SET(base->slot_id, slot_id);
   2706         CHECK_SET(base->dest_unit, dest_unit);
   2707         CHECK_SET(base->dest_port, base_dest_port);
   2708         CHECK_SET(entry->tx_unit, tx_unit);
   2709         CHECK_SET(entry->tx_port, tx_port);
   2710         CHECK_SET(entry->dest_mod, dest_mod);
   2711         CHECK_SET(entry->dest_port, dest_port);
   2712         CHECK_SET(entry->topo_idx, topo_idx);
   2713         entry->base.num_units = 0;
   2714         entry->base.num_stk_ports = 0;
   2715         break;
   2716 
   2717     case PARSE_OBJ_CPUDB_UNIT_MOD_IDS :
   2718         CPUDB_KEY_SEARCH(db_ref, current_key, entry);
   2719         if (entry == NULL) {
   2720             sal_printf("CPUDB PARSE UNIT_MOD_IDS:  Current DB key not found\n");
   2721             cmd_rv = CMD_FAIL;
   2722             break;
   2723         }
   2724         if (entry->base.num_units >= CPUDB_UNITS_MAX) {
   2725             sal_printf("CPUDB PARSE UNIT_MOD_IDS: Cannot exceed %d units\n",
   2726                        CPUDB_UNITS_MAX);
   2727             cmd_rv = CMD_FAIL;
   2728             break;
   2729         }
   2730         cur_unit = entry->base.num_units++;
   2731         entry->mod_ids[cur_unit] = mod_id;
   2732         entry->base.pref_mod_id[cur_unit] = pref_mod_id;
   2733         entry->base.mod_ids_req[cur_unit] = mod_ids_req;
   2734         break;
   2735 
   2736     case PARSE_OBJ_CPUDB_STK_PORT :
   2737         CPUDB_KEY_SEARCH(db_ref, current_key, entry);
   2738         if (entry == NULL) {
   2739             sal_printf("CPUDB PARSE STK_PORT:  Current DB key not found\n");
   2740             cmd_rv = CMD_FAIL;
   2741             break;
   2742         }
   2743         if (BCM_FAILURE(_stk_port_add(entry, unit, port, weight, base_flags,
   2744                                       flags, tx_stk_idx, rx_stk_idx,
   2745                                       tx_cpu_key, rx_cpu_key))) {
   2746             cmd_rv = CMD_FAIL;
   2747         }
   2748         break;
   2749 
   2750     case PARSE_OBJ_CPUDB_STK_PORT_STR :
   2751         CPUDB_KEY_SEARCH(db_ref, current_key, entry);
   2752         if (entry == NULL) {
   2753             sal_printf("CPUDB PARSE STK_PORT_STR:  "
   2754                        "Current DB key not found\n");
   2755             cmd_rv = CMD_FAIL;
   2756             break;
   2757         }
   2758         cmd_rv = _port_string_parse(entry, sp_string);
   2759         break;
   2760 
   2761     case PARSE_OBJ_MASTER_KEY     :
   2762         CPUDB_KEY_SEARCH(db_ref, key, entry);
   2763         if (entry == NULL) {
   2764             sal_printf("CPUDB PARSE MASTER KEY:  Entry not found: "
   2765                        CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key));
   2766             cmd_rv = CMD_FAIL;
   2767             break;
   2768         }
   2769         db_ref->master_entry = entry;
   2770         break;
   2771 
   2772     case PARSE_OBJ_LOCAL_KEY      :
   2773         CPUDB_KEY_SEARCH(db_ref, key, entry);
   2774         if (entry == NULL) {
   2775             sal_printf("CPUDB PARSE LOCAL KEY:  Entry not found: "
   2776                        CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key));
   2777             cmd_rv = CMD_FAIL;
   2778             break;
   2779         }
   2780         db_ref->local_entry = entry;
   2781         break;
   2782 
   2783     case PARSE_OBJ_TOPO_CPU       :
   2784         CPUDB_KEY_SEARCH(db_ref, key, entry);
   2785         if (entry == NULL) {
   2786             sal_printf("CPUDB PARSE LOCAL KEY:  Entry not found: "
   2787                        CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key));
   2788             cmd_rv = CMD_FAIL;
   2789             break;
   2790         }
   2791         PARSE_TP_CPU_INIT;
   2792         cpudb_entry_copy(&parse_tp_cpu->local_entry, entry);
   2793         CHECK_SET(parse_tp_cpu->version, version);
   2794         CHECK_SET(parse_tp_cpu->master_seq_num, master_seq_num);
   2795         CHECK_SET(parse_tp_cpu->flags, flags);
   2796         current_topo_sp_idx = -1;
   2797         break;
   2798 
   2799     case PARSE_OBJ_TOPO_STK_PORT  :
   2800         current_topo_sp_idx++;
   2801         if (current_topo_sp_idx >= CPUDB_STK_PORTS_MAX) {
   2802             sal_printf("CPUDB PARSE TOPO_STK_PORT: Cannot exceed %d stack "
   2803                        "ports\n", CPUDB_STK_PORTS_MAX);
   2804             cmd_rv = CMD_FAIL;
   2805             break;
   2806         }
   2807         PARSE_TP_CPU_INIT;
   2808         topo_sp = &parse_tp_cpu->tp_stk_port[current_topo_sp_idx];
   2809         CHECK_SET(topo_sp->flags, flags);
   2810         break;
   2811     case PARSE_OBJ_TOPO_TX_MOD    :
   2812         PARSE_TP_CPU_INIT;
   2813         topo_sp = &parse_tp_cpu->tp_stk_port[current_topo_sp_idx];
   2814         if (topo_sp->tx_mod_num >= TOPO_MODIDS_MAX) {
   2815             sal_printf("CPUDB PARSE TOPO_TX_MOD: Cannot exceed %d mod ids\n",
   2816                        TOPO_MODIDS_MAX);
   2817             cmd_rv = CMD_FAIL;
   2818             break;
   2819         } 
   2820         topo_sp->tx_mods[(topo_sp->tx_mod_num)++] = mod_id;
   2821         break;
   2822     case PARSE_OBJ_TOPO_RX_MOD    :
   2823         PARSE_TP_CPU_INIT;
   2824         topo_sp = &parse_tp_cpu->tp_stk_port[current_topo_sp_idx];
   2825         if (topo_sp->rx_mod_num >= TOPO_MODIDS_MAX) {
   2826             sal_printf("CPUDB PARSE TOPO_RX_MOD: Cannot exceed %d mod ids\n",
   2827                        TOPO_MODIDS_MAX);
   2828             cmd_rv = CMD_FAIL;
   2829             break;
   2830         } 
   2831         topo_sp->rx_mods[(topo_sp->rx_mod_num)++] = mod_id;
   2832         break;
   2833 
   2834     case PARSE_OBJ_TOPO_CLEAR     :   /* Clear parse topology */
   2835         PARSE_TP_CPU_INIT;
   2836         sal_memset(parse_tp_cpu, 0, sizeof(*parse_tp_cpu));
   2837         break;
   2838 
   2839     case PARSE_OBJ_TOPO_INSTALL  :
   2840         /* not supported */
   2841         break;
   2842 
   2843     case PARSE_OBJ_STACK_INSTALL  :
   2844         rv = atp_db_update(db_ref);
   2845         if (rv < 0) {
   2846             cli_out("WARNING:  ATP DB update failed %d: %s\n",
   2847                     rv, bcm_errmsg(rv));
   2848         }
   2849         rv = bcm_stack_attach_update(db_ref);
   2850         if (rv < 0) {
   2851             cli_out("ERROR:  stack attach returned %d: %s\n",
   2852                     rv, bcm_errmsg(rv));
   2853         }
   2854         break;
   2855     case PARSE_OBJ_LOCAL_ENTRY  :
   2856         /* Make a few parameters settable for local entry */
   2857         if (db_ref->local_entry == NULL) {
   2858             cli_out("ERROR:  DB parse.  Local entry not set\n");
   2859             cmd_rv = CMD_FAIL;
   2860             break;
   2861         }
   2862         entry = db_ref->local_entry;
   2863         base = &entry->base;
   2864         CHECK_SET(entry->flags, flags);
   2865         CHECK_SET(base->master_pri, master_pri);
   2866         CHECK_SET(base->slot_id, slot_id);
   2867         CHECK_SET(base->dest_unit, dest_unit);
   2868         CHECK_SET(base->dest_port, base_dest_port);
   2869         CHECK_SET(entry->tx_unit, tx_unit);
   2870         CHECK_SET(entry->tx_port, tx_port);
   2871         CHECK_SET(entry->dest_mod, dest_mod);
   2872         CHECK_SET(entry->dest_port, dest_port);
   2873         CHECK_SET(entry->topo_idx, topo_idx);
   2874         break;
   2875     default:
   2876         sal_printf("Unknown object parse\n");
   2877         cmd_rv = CMD_USAGE;
   2878         break;
   2879     }
   2880 
   2881     parse_arg_eq_done(&pt);
   2882     return cmd_rv;
   2883 }        
   2884         
   2885 
   2886 #endif  /* INCLUDE_LIB_CPUDB */