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

board.c (23149B)


      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:        board.c
      8  * Purpose:     Board driver CLI
      9  */
     10 
     11 #include <sal/types.h>
     12 #if !defined(NO_SAL_APPL)
     13 #include <sal/appl/config.h>
     14 #endif
     15 #include <appl/diag/shell.h>
     16 #include <appl/diag/system.h>
     17 #include <appl/diag/parse.h>
     18 #include <appl/diag/ctrans.h>
     19 #include <board/board.h>
     20 
     21 #include <shared/bsl.h>
     22 
     23 #if defined(INCLUDE_BOARD)
     24 
     25 char board_cmd_usage[] =
     26     "board <subcmd> [options]\n"
     27 #ifndef COMPILER_STRING_CONST_LIMIT
     28     "Subcommands:\n"
     29     "    select [name=boardname] [flags=startflags]\n"
     30     "        Attach and start a board.\n"
     31     "        If no board name is provided, probe all registered board\n"
     32     "        drivers and select the first board driver that probes\n"
     33     "        successfully.\n"
     34     "        Start flags default to 0 (cold boot). Start flags can be\n"
     35     "        numeric, or one of 'Cold', 'Warm', or 'CLear'\n"
     36     "    detach\n"
     37     "        Stop and detach the current board.\n"
     38     "    list\n"
     39     "        Display all registered boards and attributes supported by\n"
     40     "        each board.\n"
     41     "    show\n"
     42     "        Display current board state and configuration name,\n"
     43     "        description, attributes, and connections.\n"
     44     "    register builtin\n"
     45     "        Register or re-register all built in drivers.\n"
     46     "    register Name=boardname\n"
     47     "        Register or re-register a built in driver with the given name.\n"
     48     "    unregister Name=boardname\n"
     49     "        Unregister a driver with the given name.\n"
     50     "    attribute name=val\n"
     51     "        Set the board attribute 'name' to 'value'.\n"
     52     "    attribute name\n"
     53     "        Display the current value of board attribute 'name'.\n"
     54     "    attribute\n"
     55     "        Display all board attributes supported by the current board.\n"
     56     "    clear\n"
     57     "        Clear devices on current board and preserve the current board\n"
     58     "        configuration.\n"
     59 #endif
     60     ;
     61 
     62 /* Macro to distinguish between NULL and empty strings */
     63 #define S(s) ((s)?(strlen((s))?(s):"<EMPTY>"):"<NULL>")
     64 
     65 /* Macro to convert BCM errors to CMD shell errors */
     66 #define CMD_SUCCESS(x) (BCM_SUCCESS(x) ? CMD_OK : CMD_FAIL)
     67 
     68 /* Position in board_cmd_flag_list where magic numeric flags land up */
     69 #define NUM_FLAG_OFFSET 3
     70 
     71 /* Decimal number string buffer length */
     72 #define STRBUF 16
     73 
     74 /* Board start string parameters */
     75 STATIC char *board_cmd_flag_list[] = {
     76     "Cold",
     77     "Warm",
     78     "CLear",
     79     NULL, /* NUM_FLAG string */
     80     NULL
     81 };
     82 
     83 /* Flag values corresponding to the strings above in
     84    board_cmd_flag_list. This would normally have been combined with
     85    board_cmd_flag_list in a single structure, but such a structure
     86    would work with diag parser functions. */
     87 STATIC uint32 board_cmd_flag_value[] = {
     88     BOARD_START_F_COLD_BOOT,
     89     BOARD_START_F_WARM_BOOT,
     90     BOARD_START_F_CLEAR,
     91     0 /* NUM_FLAG value */
     92 };
     93 
     94 /*
     95  * Function:
     96  *     board_cmd_parse_numeric_start_flag
     97  * Purpose:
     98  *     If there's a numeric start flag, add it to the flag list
     99  * Parameters:
    100  *     args  - (IN) argument structure to scan
    101  * Returns:
    102  *     void
    103  */
    104 STATIC
    105 void board_cmd_parse_numeric_start_flag(args_t *args)
    106 {
    107     char *arg;
    108     char *value;
    109     int count;
    110 
    111     count=0;
    112     board_cmd_flag_list[NUM_FLAG_OFFSET] = NULL; /* remove any previous flag */
    113     while (ARG_CNT(args) > 0) {
    114         arg = ARG_CUR(args);
    115 
    116         /* flag format is f...=value */
    117         if (arg != NULL && (arg[0] == 'f' || arg[0] == 'F')) {
    118             value = sal_strchr(arg, '=');
    119             if (value) {
    120                 value++;
    121                 if (isint(value)) {
    122                     board_cmd_flag_list[NUM_FLAG_OFFSET] = value;
    123                     board_cmd_flag_value[NUM_FLAG_OFFSET] =
    124                         parse_integer(value);
    125                     break;
    126                 }
    127             }
    128         }
    129         count++;
    130         ARG_NEXT(args);
    131     }
    132     /* put arg count back */
    133     while (count-- > 0) {
    134         ARG_PREV(args);
    135     }
    136 }
    137 
    138 /* Returns a string corresponding to the r/w access of a board attribute */
    139 #define ATTR_ACCESS(a) ((a) ? "rw" : "ro")
    140 
    141 /*
    142  * Function:
    143  *     board_cmd_list
    144  * Purpose:
    145  *     List names and attributes of all installed board drivers.
    146  * Parameters:
    147  *     none
    148  * Returns:
    149  *     CMD_OK - success
    150  *     CMD_FAIL - failed
    151  */
    152 STATIC cmd_result_t
    153 board_cmd_list(void)
    154 {
    155     board_driver_t **driver;
    156     int rv, count, i, j;
    157 
    158     rv = board_drivers_get(0, NULL, &count);
    159 
    160     if (BCM_FAILURE(rv)) {
    161         cli_out("board_drivers_get: %s (%d)\n", bcm_errmsg(rv), rv);
    162         return CMD_FAIL;
    163     }
    164 
    165     driver = sal_alloc(count * sizeof(board_driver_t *), "board_cmd");
    166 
    167     if (!driver) {
    168         return CMD_FAIL;
    169     }
    170 
    171     rv = board_drivers_get(count, driver, &count);
    172     if (BCM_FAILURE(rv)) {
    173         cli_out("board_drivers_get: %s (%d)\n", bcm_errmsg(rv), rv);
    174         sal_free(driver);
    175         return CMD_FAIL;
    176     }
    177 
    178     for (i=0; i<count; i++) {
    179 
    180         cli_out("%s\n", driver[i]->name);
    181 
    182         for (j=0; j<driver[i]->num_attribute; j++) {
    183             cli_out("  %s [%s]\n",
    184                     driver[i]->attribute[j].name,
    185                     ATTR_ACCESS(driver[i]->attribute[j].set));
    186         }
    187     }
    188 
    189     sal_free(driver);
    190     return CMD_OK;
    191 }
    192 
    193 /*
    194  * Function:
    195  *     board_cmd_start
    196  * Purpose:
    197  *     Start a board based on parameters passed or config variables.
    198  *     If a name is given, use that name, otherwise if there's a
    199  *     "board_name" config variable, use that. When all else fails,
    200  *     probe for a board.  If the probe fails, then error out,
    201  *     otherwise attach the board.  Once the board is attached, start
    202  *     the board with the given board flags, the board flags config,
    203  *     or the default cold start flag. If the board start was
    204  *     successful, set board attributes if any attribute configs were
    205  *     found.
    206  * Parameters:
    207  *     name    - (IN) board name to start, or NULL to probe
    208  *     flagidx - (IN) start flag
    209  * Configs:
    210  *     board_name
    211  *     board_flags
    212  *     board_<attr>
    213  * Returns:
    214  *     CMD_OK - success
    215  *     CMD_FAIL - failed
    216  */
    217 STATIC cmd_result_t
    218 board_cmd_start(char *name, int flagidx)
    219 {
    220     int rv, cmd_rv, num_attr, i;
    221     uint32 flags = 0;
    222     board_attribute_t *attr;
    223 #if !defined(NO_SAL_APPL)
    224     char config_name[SAL_CONFIG_STR_MAX];
    225 #else
    226     char config_name[128];
    227 #endif
    228 
    229     cmd_rv = CMD_FAIL;
    230     attr = NULL;
    231 
    232 #if !defined(NO_SAL_APPL)
    233     if (name == NULL || sal_strlen(name) == 0) {
    234         /* if there's a config board_name, use that name */
    235         name = sal_config_get(spn_BOARD_NAME);
    236     }
    237 #endif
    238 
    239     if (name == NULL || sal_strlen(name) == 0) {
    240         /* probe */
    241         name = board_probe();
    242         if (name == NULL) {
    243             cli_out("Board probe failed\n");
    244             goto fail;
    245         }
    246     } else {
    247         /* find */
    248         if (!board_find(name)) {
    249             cli_out("Cannot find board '%s'\n", name);
    250             goto fail;
    251         }
    252     }
    253 
    254     /* attach */
    255     rv = board_attach(name);
    256     if (BCM_FAILURE(rv)) {
    257         cli_out("Cannot attach board '%s':%s (%d)\n",
    258                 name, bcm_errmsg(rv), rv);
    259         goto fail;
    260     }
    261 
    262     /* start */
    263     if (flagidx < 0) {
    264         char *flagstr = NULL;
    265 
    266 #if !defined(NO_SAL_APPL)
    267         flagstr = sal_config_get(spn_BOARD_FLAGS);
    268 #endif
    269         /* if there's a board_flags argument, use that, otherwise
    270            default to 'cold boot' */
    271 
    272         if (flagstr) {
    273             if (isint(flagstr)) {
    274                 flags = parse_integer(flagstr);
    275             } else {
    276                 cli_out("Could not parse board_flags=%s\n",flagstr);
    277                 goto fail;
    278             }
    279         } else {
    280             flags = board_cmd_flag_value[0];
    281         }
    282     }
    283 
    284     rv = board_start(flags);
    285     if (BCM_FAILURE(rv)) {
    286         cli_out("Cannot start %s(%08x):%s (%d)\n",
    287                 name, flags, bcm_errmsg(rv), rv);
    288         board_detach();
    289         goto fail;
    290     }
    291 
    292     /* Go though the writable attributes, and see if there are
    293        any matching configs. If there are, then set those
    294        attributes */
    295 
    296     rv = board_attributes_get(0, NULL, &num_attr);
    297     if (BCM_FAILURE(rv)) {
    298         cli_out("Cannot get board attributes for %s:%s (%d)\n",
    299                 name, bcm_errmsg(rv), rv);
    300         goto fail;
    301     }
    302 
    303     attr = sal_alloc(num_attr * sizeof(board_attribute_t),
    304                        "board_cmd_start");
    305 
    306     if (attr == NULL) {
    307         cli_out("Cannot alloc memory for attributes\n");
    308         goto fail;
    309     }
    310 
    311     rv = board_attributes_get(num_attr, attr, &num_attr);
    312     if (BCM_FAILURE(rv)) {
    313         cli_out("Cannot get board attributes for %s:%s (%d)\n",
    314                 name, bcm_errmsg(rv), rv);
    315         goto fail;
    316     }
    317 
    318     /* Set board attributes if matching config variables are found.
    319        Set variables for all attributes.
    320     */
    321     for (i=0; i<num_attr; i++) {
    322         sal_sprintf(config_name, "board_%s", attr[i].name);
    323 #if !defined(NO_SAL_APPL)
    324         if (attr[i].set) {
    325             char *value;
    326 
    327             value = sal_config_get(config_name);
    328             if (value) {
    329                 if (isint(value)) {
    330                     rv = board_attribute_set(config_name,
    331                                              parse_integer(value));
    332                     if (BCM_FAILURE(rv)) {
    333                         cli_out("Cannot set board attribute %s=%s:%s (%d)\n",
    334                                 config_name, value, bcm_errmsg(rv), rv);
    335                         goto fail;
    336                     }
    337                 } else {
    338                     cli_out("Could not parse %s=%s\n",
    339                             config_name, value);
    340                     goto fail;
    341                 }
    342             }
    343         }
    344 #endif
    345         if (attr[i].get) {
    346             int int_value;
    347             char int_value_str[STRBUF];
    348 
    349             rv = board_attribute_get(config_name, &int_value);
    350             if (BCM_SUCCESS(rv)) {
    351                 sal_sprintf(int_value_str, "%d", int_value);
    352                 if (var_set(config_name, int_value_str, FALSE, FALSE) < 0) {
    353                     goto fail;
    354                 }
    355             }
    356         }
    357     }
    358 
    359     /* Set board variables */
    360     if (var_set("board_name", board_name(), FALSE, FALSE) < 0) {
    361         goto fail;
    362     }
    363 
    364     if (var_set(board_name(), "1", FALSE, FALSE) < 0) {
    365         goto fail;
    366     }
    367 
    368     cmd_rv = CMD_OK;
    369 
    370  fail:
    371     if (attr) {
    372         sal_free(attr);
    373     }
    374 
    375     return cmd_rv;
    376 }
    377 
    378 /*
    379  * Function:
    380  *     board_cmd_register
    381  * Purpose:
    382  *     Register a builtin driver of the given name
    383  * Parameters:
    384  *      name - (IN) board driver to register
    385  * Returns:
    386  *     CMD_OK - success
    387  *     CMD_FAIL - failed
    388  */
    389 STATIC cmd_result_t
    390 board_cmd_register(char *name)
    391 {
    392     board_driver_t **driver, *add;
    393     int count, i;
    394     int rv, cmd_rv = CMD_FAIL;
    395 
    396     driver = NULL;
    397 
    398     rv = board_driver_builtins_get(0, NULL, &count);
    399 
    400     if (BCM_FAILURE(rv)) {
    401         cli_out("board_driver_builtins_get: %s (%d)\n", bcm_errmsg(rv), rv);
    402         goto fail;
    403     }
    404 
    405     driver = sal_alloc(count * sizeof(board_driver_t *), "board_cmd");
    406 
    407     if (!driver) {
    408         cli_out("Out of memory\n");
    409         goto fail;
    410     }
    411 
    412     rv = board_driver_builtins_get(count, driver, &count);
    413     if (BCM_FAILURE(rv)) {
    414         cli_out("board_driver_builtins_get: %s (%d)\n", bcm_errmsg(rv), rv);
    415         goto fail;
    416     }
    417 
    418     add = NULL;
    419     for (i=0; i<count; i++) {
    420 
    421         if (!sal_strcmp(name, driver[i]->name)) {
    422             add = driver[i];
    423             break;
    424         }
    425     }
    426 
    427     if (add) {
    428         int rv;
    429 
    430         rv = board_driver_add(add);
    431         if (BCM_SUCCESS(rv)) {
    432             cmd_rv = CMD_OK;
    433         } else {
    434             cli_out("Cannot add board driver %s:%s (%d)\n",
    435                     name, bcm_errmsg(rv), rv);
    436         }
    437     } else {
    438         cli_out("Board driver %s not found\n", name);
    439     }
    440 
    441  fail:
    442     if (driver) {
    443         sal_free(driver);
    444     }
    445 
    446     return cmd_rv;
    447 }
    448 
    449 /*
    450  * Function:
    451  *     board_cmd_unregister
    452  * Purpose:
    453  *     Register a driver of the given name
    454  * Parameters:
    455  *     name - (IN) board driver to unregister
    456  * Returns:
    457  *     CMD_OK - success
    458  *     CMD_FAIL - failed
    459  */
    460 STATIC cmd_result_t
    461 board_cmd_unregister(char *name)
    462 {
    463     board_driver_t **driver, *del;
    464     int count, i;
    465     int rv, cmd_rv = CMD_FAIL;
    466 
    467     rv = board_drivers_get(0, NULL, &count);
    468     if (BCM_FAILURE(rv)) {
    469         cli_out("board_drivers_get: %s (%d)\n", bcm_errmsg(rv), rv);
    470         return CMD_FAIL;
    471     }
    472 
    473     driver = sal_alloc(count * sizeof(board_driver_t *), "board_cmd");
    474 
    475     if (!driver) {
    476         cli_out("Out of memory\n");
    477         return CMD_FAIL;
    478     }
    479 
    480     rv = board_drivers_get(count, driver, &count);
    481     if (BCM_FAILURE(rv)) {
    482         cli_out("board_drivers_get: %s (%d)\n", bcm_errmsg(rv), rv);
    483         sal_free(driver);
    484         return CMD_FAIL;
    485     }
    486 
    487     del = NULL;
    488     for (i=0; i<count; i++) {
    489 
    490         if (!sal_strcmp(name, driver[i]->name)) {
    491             del = driver[i];
    492             break;
    493         }
    494 
    495     }
    496     if (del) {
    497         int rv;
    498 
    499         rv = board_driver_delete(del);
    500         if (BCM_SUCCESS(rv)) {
    501             cmd_rv = CMD_OK;
    502         } else {
    503             cli_out("Cannot delete board driver %s:%s (%d)\n",
    504                     name, bcm_errmsg(rv), rv);
    505         }
    506     } else {
    507         cli_out("Board driver %s not registered\n", name);
    508     }
    509 
    510     sal_free(driver);
    511     return cmd_rv;
    512 }
    513 
    514 /*
    515  * Function:
    516  *     board_cmd_attr_print
    517  * Purpose:
    518  *     Print short or long information about a board attribute
    519  * Parameters:
    520  *      attr - (IN) attribute to print
    521  *      full - (IN) TRUE if full information is to be printed
    522  * Returns:
    523  *     BCM_E_NONE - success
    524  *     BCM_E_XXX  - failed
    525  */
    526 STATIC int
    527 board_cmd_attr_print(board_attribute_t *attr, int full)
    528 {
    529     int value, rv;
    530     char valstr[STRBUF], *spacer, *units;
    531 
    532     rv = board_attribute_get(attr->name, &value);
    533 
    534     if (BCM_SUCCESS(rv)) {
    535 
    536         /* print according to attribute format */
    537         sal_sprintf(valstr, attr->format ? attr->format : "%d", value);
    538 
    539         if (full) {
    540             /* get units if applicable */
    541             if (attr->units) {
    542                 spacer = " ";
    543                 units = attr->units;
    544             } else {
    545                 spacer = units = "";
    546             }
    547 
    548             /* display attribute */
    549             cli_out("  %-10s [%s]=%s%s%s\n",
    550                     attr->name,
    551                     ATTR_ACCESS(attr->set),
    552                     valstr,
    553                     spacer,
    554                     units);
    555         } else {
    556             cli_out("%s\n", valstr);
    557         }
    558     } else {
    559         cli_out("  %s: %s (%d)\n", attr->name, bcm_errmsg(rv), rv);
    560     }
    561 
    562     return rv;
    563 }
    564 
    565 /*
    566  * Function:
    567  *     board_cmd_attribute_list
    568  * Purpose:
    569  *     Print arributes for the current board
    570  * Parameters:
    571  *     name - (IN) Specific attribute to print, or NULL for all attributes
    572  * Returns:
    573  *     CMD_OK - success
    574  *     CMD_FAIL - failed
    575  */
    576 STATIC cmd_result_t
    577 board_cmd_attribute_list(char *name)
    578 {
    579     board_attribute_t *attr;
    580     int rv, count, i;
    581 
    582     rv = board_attributes_get(0, NULL, &count);
    583     if (BCM_FAILURE(rv)) {
    584         cli_out("board_attributes_get: %s (%d)\n", bcm_errmsg(rv), rv);
    585         return CMD_FAIL;
    586     }
    587 
    588     attr = sal_alloc(count * sizeof(board_attribute_t), "board_cmd");
    589 
    590     if (!attr) {
    591         cli_out("Out of memory\n");
    592         return CMD_FAIL;
    593     }
    594 
    595     rv = board_attributes_get(count, attr, &count);
    596     if (BCM_FAILURE(rv)) {
    597         cli_out("board_attributes_get: %s (%d)\n", bcm_errmsg(rv), rv);
    598         sal_free(attr);
    599         return CMD_FAIL;
    600     }
    601 
    602     for (i=0; i<count; i++) {
    603         if (name == NULL || !sal_strcmp(name, attr[i].name)) {
    604             board_cmd_attr_print(&attr[i], TRUE);
    605         }
    606     }
    607 
    608     sal_free(attr);
    609     return CMD_OK;
    610 }
    611 
    612 /*
    613  * Function:
    614  *     board_cmd_attribute_set
    615  * Purpose:
    616  *     Set the attribute of the given name to the given value
    617  * Parameters:
    618  *     name  - (IN) attribute name
    619  *     value - (IN) value
    620  * Returns:
    621  *     CMD_OK - success
    622  *     CMD_FAIL - failed
    623  */
    624 STATIC cmd_result_t
    625 board_cmd_attribute_set(char *name, char *value)
    626 {
    627     if (isint(value)) {
    628         return CMD_SUCCESS(board_attribute_set(name, parse_integer(value)));
    629     }
    630 
    631     return CMD_FAIL;
    632 }
    633 
    634 #define MAX_CALL 4
    635 #define MAX_NAME 16
    636 
    637 /*
    638  * Function:
    639  *     board_cmd_devport_name
    640  * Purpose:
    641  *     Pretty print a gport DEVPORT name into a circular buffer. This
    642  *     intended to allow multiple calls to this function from printfs.
    643  * Parameters:
    644  *      gport - (IN) gport to print
    645  * Returns:
    646  *     static string name of port
    647  */
    648 STATIC char *
    649 board_cmd_devport_name(bcm_gport_t gport)
    650 {
    651     int unit;
    652     bcm_port_t port;
    653     char *s;
    654     static char name[MAX_CALL][MAX_NAME];
    655     static int idx;
    656 
    657     unit = BCM_GPORT_DEVPORT_DEVID_GET(gport);
    658     port = BCM_GPORT_DEVPORT_PORT_GET(gport);
    659     s = name[idx++];
    660     if (idx >= MAX_CALL) {
    661         idx = 0;
    662     }
    663     if (bcm_unit_valid(unit) && port >= 0) {
    664         sal_sprintf(s, "%d:%s", unit, bcm_port_name(unit, port));
    665     } else {
    666         sal_sprintf(s, "%08x", gport);
    667     }
    668     return s;
    669 }
    670 
    671 /*
    672  * Function:
    673  *     board_cmd_connection_print
    674  * Purpose:
    675  *     Pretty print a board connection
    676  * Parameters:
    677  *     connection  - (IN) connection to print
    678  * Returns:
    679  *     void
    680  */
    681 STATIC void
    682 board_cmd_connection_print(board_connection_t *connection)
    683 {
    684     if (connection->to != BCM_GPORT_TYPE_NONE) {
    685         cli_out("  %8s -> %-8s\n",
    686                 board_cmd_devport_name(connection->from),
    687                 board_cmd_devport_name(connection->to));
    688     } else {
    689         cli_out("  %s [stack]\n", board_cmd_devport_name(connection->from));
    690     }
    691 }
    692 
    693 /*
    694  * Function:
    695  *     board_cmd_connection_list
    696  * Purpose:
    697  *     List all connections for the current board
    698  * Parameters:
    699  *     none
    700  * Returns:
    701  *     CMD_OK - success
    702  *     CMD_FAIL - failed
    703  */
    704 STATIC cmd_result_t
    705 board_cmd_connection_list(void)
    706 {
    707     board_connection_t *conn;
    708     int count, i;
    709 
    710     if (BCM_FAILURE(board_connections_get(0, NULL, &count))) {
    711         return CMD_FAIL;
    712     }
    713 
    714     conn = sal_alloc(count * sizeof(board_connection_t), "board_cmd");
    715 
    716     if (!conn) {
    717         return CMD_FAIL;
    718     }
    719 
    720     if (BCM_FAILURE(board_connections_get(count, conn, &count))) {
    721         sal_free(conn);
    722         return CMD_FAIL;
    723     }
    724 
    725     for (i=0; i<count; i++) {
    726         board_cmd_connection_print(&conn[i]);
    727     }
    728 
    729     sal_free(conn);
    730     return CMD_OK;
    731 }
    732 
    733 /*
    734  * Function:
    735  *     board_cmd_show
    736  * Purpose:
    737  *     Print all information about the current board
    738  * Parameters:
    739  *     none
    740  * Returns:
    741  *     CMD_OK - success
    742  *     CMD_FAIL - failed
    743  */
    744 STATIC cmd_result_t
    745 board_cmd_show(void)
    746 {
    747     cli_out("Name:\n  %s\n", S(board_name()));
    748     cli_out("Description:\n  %s\n", S(board_description()));
    749     cli_out("Attributes:\n");
    750     board_cmd_attribute_list(NULL);
    751     cli_out("Connections:\n");
    752     board_cmd_connection_list();
    753     return CMD_OK;
    754 }
    755 
    756 
    757 /*
    758  * Function:
    759  *     board_cmd
    760  * Purpose:
    761  *     Board Diag shell command handler
    762  * Parameters:
    763  *      unit - (IN) current diag shell unit
    764  *      args - arglist
    765  * Returns:
    766  *     CMD_OK - success
    767  *     CMD_FAIL - failed
    768  */
    769 cmd_result_t
    770 board_cmd(int unit, args_t *args)
    771 {
    772     char *subcmd;
    773     int sublen;
    774     int rv, cmd_rv;
    775     static int init;
    776     parse_table_t pt;
    777 
    778     if (!init) {
    779         rv = board_init();
    780         if (BCM_FAILURE(rv)) {
    781             cli_out("board_init failed:%s (%d)\n", bcm_errmsg(rv), rv);
    782             return CMD_FAIL;
    783         }
    784         rv = board_driver_builtins_add();
    785         if (BCM_FAILURE(rv)) {
    786             cli_out("board_driver_builtins_add failed:%s (%d)\n",
    787                     bcm_errmsg(rv), rv);
    788             return CMD_FAIL;
    789         }
    790         init=TRUE;
    791     }
    792 
    793     if ((subcmd = ARG_GET(args)) == NULL) {
    794         return board_cmd_show();
    795     }
    796 
    797     sublen=sal_strlen(subcmd);
    798     if (sal_strncasecmp(subcmd, "show", sublen) == 0) {
    799         return board_cmd_show();
    800 
    801     } else if (sal_strncasecmp(subcmd, "select", sublen) == 0) {
    802         char *name;
    803         int  flagidx;
    804 
    805         name=NULL;
    806         flagidx=-1;
    807         /* if flags are numeric, add to flag multi list */
    808 
    809         if (ARG_CNT(args) > 0) {
    810             board_cmd_parse_numeric_start_flag(args);
    811             parse_table_init(unit, &pt);
    812             parse_table_add(&pt, "Name", PQ_STRING, 0,  &name, 0);
    813             parse_table_add(&pt, "Flags", PQ_DFL | PQ_MULTI, 0, &flagidx,
    814                             board_cmd_flag_list);
    815 
    816             if (parse_arg_eq(args, &pt)) {
    817                 cli_out("select name:%s flag:%08x\n",
    818                         S(name), board_cmd_flag_value[flagidx]);
    819             } else {
    820                 return CMD_USAGE;
    821             }
    822         } else {
    823             name = "";
    824         }
    825         return board_cmd_start(name, flagidx);
    826 
    827     } else if (sal_strncasecmp(subcmd, "detach", sublen) == 0) {
    828         cli_out("detach\n");
    829         rv = board_detach();
    830         return CMD_SUCCESS(rv);
    831 
    832     } else if (sal_strncasecmp(subcmd, "list", sublen) == 0) {
    833         return board_cmd_list();
    834     } else if (sal_strncasecmp(subcmd, "register", sublen) == 0) {
    835         char *builtin;
    836 
    837         builtin = ARG_CUR(args);
    838         if (builtin != NULL &&
    839             sal_strncasecmp(builtin, "builtin", sal_strlen(builtin)) == 0) {
    840             ARG_NEXT(args);
    841             cli_out("register builtin\n");
    842             rv = board_driver_builtins_add();
    843             return CMD_SUCCESS(rv);
    844         } else {
    845             char *name;
    846 
    847             name=NULL;
    848             parse_table_init(unit, &pt);
    849             parse_table_add(&pt, "Name", PQ_STRING, 0,  &name, 0);
    850             if (parse_arg_eq(args, &pt)) {
    851                 cmd_rv = board_cmd_register(name);
    852             } else {
    853                 cmd_rv = CMD_USAGE;
    854             }
    855         }
    856         return cmd_rv;
    857     } else if (sal_strncasecmp(subcmd, "unregister", sublen) == 0) {
    858         char *name;
    859 
    860         name=NULL;
    861         parse_table_init(unit, &pt);
    862         parse_table_add(&pt, "Name", PQ_STRING, 0,  &name, 0);
    863         if (parse_arg_eq(args, &pt)) {
    864             cmd_rv = board_cmd_unregister(name);
    865         } else {
    866             cmd_rv = CMD_USAGE;
    867         }
    868         return cmd_rv;
    869     } else if (sal_strncasecmp(subcmd, "attribute", sublen) == 0) {
    870         char *name, *value;
    871 
    872         name = ARG_CUR(args);
    873         if (name == NULL) {
    874             cmd_rv = board_cmd_attribute_list(NULL);
    875         } else {
    876             value = sal_strchr(name, '=');
    877 
    878             if (!value) {
    879                 board_cmd_attribute_list(name);
    880             } else {
    881                 *value='\0';
    882                 value++;
    883                 board_cmd_attribute_set(name, value);
    884             }
    885             ARG_NEXT(args);
    886         }
    887         return CMD_OK;
    888     } else if (sal_strncasecmp(subcmd, "clear", sublen) == 0) {
    889         cli_out("clear\n");
    890         return CMD_OK;
    891     } else {
    892         cli_out("Subcommand not found: %s\n", subcmd);
    893         return CMD_USAGE;
    894     }
    895 
    896     return CMD_OK;
    897 }
    898 
    899 #endif /* INCLUDE_BAORD */