1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Milan Jurik. All rights reserved.
  24  * Copyright (c) 2018, Joyent, Inc.
  25  */
  26 
  27 /*
  28  * This is the user interface module for the pcitool.  It checks commandline
  29  * arguments and options and stores them in a pcitool_uiargs_t structure passed
  30  * back to the rest of the program for processing.
  31  *
  32  * Please see pcitool_usage.c for a complete commandline description.
  33  */
  34 
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <sys/inttypes.h>
  39 #include <sys/types.h>
  40 #include <sys/param.h>
  41 #include <strings.h>
  42 #include <errno.h>
  43 #include <sys/pci.h>
  44 
  45 #include <sys/pci_tools.h>
  46 
  47 #include "pcitool_ui.h"
  48 
  49 /*
  50  * Uncomment the following for useful debugging / development options for this
  51  * module only.
  52  */
  53 
  54 /* #define      DEBUG   1               */
  55 /* #define      STANDALONE      1       */
  56 
  57 #define         DEVNAME_START_PCI       "/pci"
  58 #define         DEVNAME_START_NIU       "/niu"
  59 
  60 /* Default read/write size when -s not specified. */
  61 #define DEFAULT_SIZE    4
  62 
  63 /* For get_value64 */
  64 #define HEX_ONLY        B_TRUE
  65 #define BASE_BY_PREFIX  B_FALSE
  66 
  67 #define BITS_PER_BYTE   8
  68 
  69 /*
  70  * This defines which main options can be specified by the user.
  71  * Options with colons after them require arguments.
  72  */
  73 static char *opt_string = ":n:d:i:m:p:rw:o:s:e:b:vaqlcxgy";
  74 
  75 /* This defines options used singly and only by themselves (no nexus). */
  76 static char *no_dev_opt_string = "ahpqv";
  77 
  78 static void print_bad_option(char *argv[], int optopt, char *optarg);
  79 static boolean_t get_confirmation(void);
  80 static int get_value64(char *value_str, uint64_t *value, boolean_t hex_only);
  81 static int parse_nexus_opts(char *input, uint64_t *flags_arg, uint8_t *bank_arg,
  82     uint64_t *base_addr_arg);
  83 static int extract_bdf_arg(char *cvalue, char *fld, uint64_t fld_flag,
  84     uint64_t *all_flags, uint8_t *ivalue);
  85 static int extract_bdf(char *value, char **bvalue_p, char **dvalue_p,
  86     char **fvalue_p);
  87 static int parse_device_opts(char *input, uint64_t *flags_arg,
  88     uint8_t *bus_arg, uint8_t *device_arg, uint8_t *func_arg,
  89     uint8_t *bank_arg);
  90 static int parse_ino_opts(char *input, uint64_t *flags_arg,
  91     uint32_t *cpu_arg, uint8_t *ino_arg);
  92 static int parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg);
  93 static int parse_intr_set_opts(char *input, uint64_t *flags_arg,
  94     uint32_t *cpu_arg);
  95 static int parse_probeone_opts(char *input, uint64_t *flags_arg,
  96     uint8_t *bus_arg, uint8_t *device_arg, uint8_t *func_arg);
  97 
  98 #ifdef DEBUG
  99 void dump_struct(pcitool_uiargs_t *dump_this);
 100 #endif
 101 
 102 /* Exported functions. */
 103 
 104 /*
 105  * Main commandline argument parsing routine.
 106  *
 107  * Takes argc and argv straight from the commandline.
 108  * Returns a pcitool_uiargs_t with flags of options specified, and values
 109  * associated with them.
 110  */
 111 int
 112 get_commandline_args(int argc, char *argv[], pcitool_uiargs_t *parsed_args)
 113 {
 114         int c;                          /* Current option being processed. */
 115         boolean_t error = B_FALSE;
 116         boolean_t confirm = B_FALSE;
 117         uint64_t recv64;
 118 
 119         /* Needed for getopt(3C) */
 120         extern char *optarg;    /* Current commandline string. */
 121         extern int optind;      /* Index of current commandline string. */
 122         extern int optopt;      /* Option (char) which is missing an operand. */
 123         extern int opterr;      /* Set to 0 to disable getopt err reporting. */
 124 
 125         opterr = 0;
 126 
 127         bzero(parsed_args, sizeof (pcitool_uiargs_t));
 128 
 129         /* No args.  probe mode accounting for bus ranges, nonverbose. */
 130         if (argc == 1) {
 131                 usage(argv[0]);
 132                 parsed_args->flags = 0;
 133                 return (SUCCESS);
 134         }
 135 
 136         /* 1st arg is not a device name. */
 137         if ((strstr(argv[1], DEVNAME_START_PCI) != argv[1]) &&
 138             (strstr(argv[1], DEVNAME_START_NIU) != argv[1])) {
 139 
 140                 /* Default is to probe all trees accounting for bus ranges. */
 141                 parsed_args->flags = PROBEALL_FLAG | PROBERNG_FLAG;
 142 
 143                 /* Loop thru the options until complete or an error is found. */
 144                 while (((c = getopt(argc, argv, no_dev_opt_string)) != -1) &&
 145                     (error == B_FALSE)) {
 146 
 147                         switch (c) {
 148 
 149                         /* Help requested. */
 150                         case 'h':
 151                                 usage(argv[0]);
 152                                 parsed_args->flags = 0;
 153                                 return (SUCCESS);
 154 
 155                         case 'p':
 156                                 /* Take default probe mode */
 157                                 break;
 158 
 159                         case 'a':
 160                                 /*
 161                                  * Enable display of ALL bus numbers.
 162                                  *
 163                                  * This takes precidence over PROBERNG as -a
 164                                  * is explicitly specified.
 165                                  */
 166                                 parsed_args->flags &= ~PROBERNG_FLAG;
 167                                 break;
 168 
 169                         case 'q':
 170                                 parsed_args->flags |= QUIET_FLAG;
 171                                 break;
 172 
 173                         /* Verbose mode for full probe. */
 174                         case 'v':
 175                                 parsed_args->flags |= VERBOSE_FLAG;
 176                                 break;
 177 
 178                         default:
 179                                 error = B_TRUE;
 180                                 break;
 181                         }
 182                 }
 183 
 184                 /* Check for values straggling at the end of the command. */
 185                 if (optind != argc) {
 186                         (void) fprintf(stderr, "%s: Unrecognized parameter "
 187                             "at the end of the command.\n", argv[0]);
 188                         error = B_TRUE;
 189                 }
 190 
 191                 if (error) {
 192                         print_bad_option(argv, optopt, optarg);
 193                         return (FAILURE);
 194                 }
 195 
 196                 return (SUCCESS);
 197         }
 198 
 199         /* Device node specified on commandline. */
 200 
 201         /* Skip argv[1] before continuing below. */
 202         optind++;
 203 
 204         /* Loop through the options until complete or an error is found. */
 205         while (((c = getopt(argc, argv, opt_string)) != -1) &&
 206             (error == B_FALSE)) {
 207 
 208                 switch (c) {
 209 
 210                 /* Nexus */
 211                 case 'n':
 212                         if (parsed_args->flags & (LEAF_FLAG |
 213                             NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
 214                                 (void) fprintf(stderr, "%s: -n set with "
 215                                     "-d, -p or -i or is set twice\n", argv[0]);
 216                                 error = B_TRUE;
 217                                 break;
 218                         }
 219                         parsed_args->flags |= NEXUS_FLAG;
 220                         if (parse_nexus_opts(optarg, &parsed_args->flags,
 221                             &parsed_args->bank, &parsed_args->base_address) !=
 222                             SUCCESS) {
 223                                 (void) fprintf(stderr,
 224                                     "%s: Error parsing -n options\n", argv[0]);
 225                                 error = B_TRUE;
 226                                 break;
 227                         }
 228                         break;
 229 
 230                 /* Device (leaf node) */
 231                 case 'd':
 232                         if (parsed_args->flags & (LEAF_FLAG |
 233                             NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
 234                                 (void) fprintf(stderr, "%s: -d set with "
 235                                     "-n, -p or -i or is set twice\n", argv[0]);
 236                                 error = B_TRUE;
 237                                 break;
 238                         }
 239                         parsed_args->flags |= LEAF_FLAG;
 240                         if (parse_device_opts(optarg, &parsed_args->flags,
 241                             &parsed_args->bus, &parsed_args->device,
 242                             &parsed_args->function,
 243                             &parsed_args->bank) != SUCCESS) {
 244                                 (void) fprintf(stderr,
 245                                     "%s: Error parsing -d options\n", argv[0]);
 246                                 error = B_TRUE;
 247                                 break;
 248                         }
 249                         break;
 250 
 251                 /* Interrupt */
 252                 case 'i':
 253                         if (parsed_args->flags & (LEAF_FLAG |
 254                             NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
 255                                 (void) fprintf(stderr, "%s: -i set with -m, "
 256                                     "-n, -d or -p or is set twice\n", argv[0]);
 257                                 error = B_TRUE;
 258                                 break;
 259                         }
 260                         parsed_args->flags |= INTR_FLAG;
 261 
 262                         /* parse input to get ino value. */
 263                         if (parse_ino_opts(optarg, &parsed_args->flags,
 264                             &parsed_args->old_cpu,
 265                             &parsed_args->intr_ino) != SUCCESS) {
 266                                 (void) fprintf(stderr,
 267                                     "%s: Error parsing interrupt options\n",
 268                                     argv[0]);
 269                                 error = B_TRUE;
 270                         }
 271                         break;
 272                 /* Interrupt */
 273                 case 'm':
 274                         if (parsed_args->flags & (LEAF_FLAG |
 275                             NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
 276                                 (void) fprintf(stderr, "%s: -m set with -i, "
 277                                     "-n, -d or -p or is set twice\n", argv[0]);
 278                                 error = B_TRUE;
 279                                 break;
 280                         }
 281                         parsed_args->flags |= INTR_FLAG;
 282 
 283                         /* parse input to get msi value. */
 284                         if (parse_msi_opts(optarg, &parsed_args->flags,
 285                             &parsed_args->intr_msi) != SUCCESS) {
 286                                 (void) fprintf(stderr,
 287                                     "%s: Error parsing interrupt options\n",
 288                                     argv[0]);
 289                                 error = B_TRUE;
 290                         }
 291                         break;
 292                 /* Probe */
 293                 case 'p':
 294                         if (parsed_args->flags & (LEAF_FLAG |
 295                             NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
 296                                 (void) fprintf(stderr, "%s: -p set with "
 297                                     "-n, -d or -i or is set twice\n", argv[0]);
 298                                 error = B_TRUE;
 299                                 break;
 300                         }
 301 
 302                         /* Process -p with no dedicated options to it. */
 303                         if (optarg[0] == '-') {
 304                                 optind--;
 305 
 306                                 /* Probe given tree observing ranges */
 307                                 parsed_args->flags |=
 308                                     (PROBETREE_FLAG | PROBERNG_FLAG);
 309                                 continue;
 310                         }
 311 
 312                         /* parse input to get ino value. */
 313                         if (parse_probeone_opts(optarg, &parsed_args->flags,
 314                             &parsed_args->bus, &parsed_args->device,
 315                             &parsed_args->function) != SUCCESS) {
 316                                 (void) fprintf(stderr,
 317                                     "%s: Error parsing probe options\n",
 318                                     argv[0]);
 319                                 error = B_TRUE;
 320                         } else {
 321                                 /*
 322                                  * parse_probeone_opts found options to
 323                                  * set up bdf.
 324                                  */
 325                                 parsed_args->flags |= PROBEDEV_FLAG;
 326                         }
 327                         break;
 328 
 329                 /* Probe all busses */
 330                 case 'a':
 331                         /* Must follow -p, and -p must have no bdf. */
 332                         if (!(parsed_args->flags & PROBETREE_FLAG)) {
 333                                 error = B_TRUE;
 334                                 break;
 335                         }
 336 
 337                         parsed_args->flags &= ~PROBERNG_FLAG;
 338                         break;
 339 
 340                 /* Read */
 341                 case 'r':
 342                         if (!(parsed_args->flags &
 343                             (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) {
 344                                 error = B_TRUE;
 345                                 break;
 346                         }
 347 
 348                         /*
 349                          * Allow read and write to be set together for now,
 350                          * since this means write then read back for device and
 351                          * nexus accesses.  Check for this and disallow with
 352                          * interrupt command later.
 353                          */
 354                         parsed_args->flags |= READ_FLAG;
 355                         break;
 356 
 357                 /* Write */
 358                 case 'w':
 359                         if (!(parsed_args->flags &
 360                             (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) {
 361                                 error = B_TRUE;
 362                                 break;
 363                         }
 364                         if (parsed_args->flags & WRITE_FLAG) {
 365                                 (void) fprintf(stderr, "%s: -w set twice\n",
 366                                     argv[0]);
 367                                 error = B_TRUE;
 368                                 break;
 369                         }
 370 
 371                         /*
 372                          * For device and nexus, get a single register value
 373                          * to write.
 374                          */
 375                         if (parsed_args->flags & (NEXUS_FLAG | LEAF_FLAG)) {
 376                                 parsed_args->flags |= WRITE_FLAG;
 377                                 if (get_value64(optarg,
 378                                     &parsed_args->write_value, HEX_ONLY) !=
 379                                     SUCCESS) {
 380                                         (void) fprintf(stderr,
 381                                             "%s: Error reading value to "
 382                                             "write.\n", argv[0]);
 383                                         error = B_TRUE;
 384                                         break;
 385                                 }
 386 
 387                         /* For interrupt,  parse input to get cpu value. */
 388                         } else if (parsed_args->flags & INTR_FLAG) {
 389                                 parsed_args->flags |= WRITE_FLAG;
 390                                 if (parse_intr_set_opts(optarg,
 391                                     &parsed_args->flags,
 392                                     &parsed_args->intr_cpu) != SUCCESS) {
 393                                         (void) fprintf(stderr, "%s: Error "
 394                                             "parsing interrupt options.\n",
 395                                             argv[0]);
 396                                         error = B_TRUE;
 397                                         break;
 398                                 }
 399 
 400                         } else {
 401                                 error = B_TRUE;
 402                                 break;
 403                         }
 404                         break;
 405 
 406                 /* Offset */
 407                 case 'o':
 408                         if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
 409                                 error = B_TRUE;
 410                                 break;
 411                         }
 412                         if (parsed_args->flags & OFFSET_FLAG) {
 413                                 (void) fprintf(stderr, "%s: -o set twice\n",
 414                                     argv[0]);
 415                                 error = B_TRUE;
 416                                 break;
 417                         }
 418                         parsed_args->flags |= OFFSET_FLAG;
 419                         if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) {
 420                                 (void) fprintf(stderr,
 421                                     "%s: Error in offset argument\n", argv[0]);
 422                                 error = B_TRUE;
 423                                 break;
 424                         }
 425                         parsed_args->offset = (uint32_t)recv64;
 426                         if (parsed_args->offset != recv64) {
 427                                 (void) fprintf(stderr, "%s: Offset argument "
 428                                     "too large for 32 bits\n", argv[0]);
 429                                 error = B_TRUE;
 430                                 break;
 431                         }
 432                         break;
 433 
 434                 /* Size */
 435                 case 's':
 436                         if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
 437                                 error = B_TRUE;
 438                                 break;
 439                         }
 440                         if (parsed_args->flags & SIZE_FLAG) {
 441                                 (void) fprintf(stderr, "%s: -s set twice\n",
 442                                     argv[0]);
 443                                 error = B_TRUE;
 444                                 break;
 445                         }
 446                         parsed_args->flags |= SIZE_FLAG;
 447                         if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) {
 448                                 (void) fprintf(stderr,
 449                                     "%s: Error in size argument\n", argv[0]);
 450                                 error = B_TRUE;
 451                                 break;
 452                         }
 453                         switch (recv64) {
 454                         case 1:
 455                         case 2:
 456                         case 4:
 457                         case 8:
 458                                 break;
 459                         default:
 460                                 error = B_TRUE;
 461                                 (void) fprintf(stderr,
 462                                     "%s: Error in size argument\n", argv[0]);
 463                                 break;
 464                         }
 465                         parsed_args->size |= (uint8_t)recv64;
 466                         break;
 467 
 468                 /* Endian. */
 469                 case 'e':
 470                         if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
 471                                 error = B_TRUE;
 472                                 break;
 473                         }
 474                         if (parsed_args->flags & ENDIAN_FLAG) {
 475                                 (void) fprintf(stderr, "%s: -e set twice\n",
 476                                     argv[0]);
 477                                 error = B_TRUE;
 478                                 break;
 479                         }
 480                         parsed_args->flags |= ENDIAN_FLAG;
 481 
 482                         /* Only a single character allowed. */
 483                         if (optarg[1] != '\0') {
 484                                 (void) fprintf(stderr,
 485                                     "%s: Error in endian argument\n", argv[0]);
 486                                 error = B_TRUE;
 487                                 break;
 488                         }
 489 
 490                         switch (optarg[0]) {
 491                         case 'b':
 492                                 parsed_args->big_endian = B_TRUE;
 493                                 break;
 494                         case 'l':
 495                                 break;
 496                         default:
 497                                 (void) fprintf(stderr,
 498                                     "%s: Error in endian argument\n", argv[0]);
 499                                 error = B_TRUE;
 500                                 break;
 501                         }
 502                         break;
 503 
 504                 /* (Byte)dump */
 505                 case 'b':
 506                         if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
 507                                 error = B_TRUE;
 508                                 break;
 509                         }
 510                         if (parsed_args->flags & BYTEDUMP_FLAG) {
 511                                 (void) fprintf(stderr, "%s: -b set twice\n",
 512                                     argv[0]);
 513                                 error = B_TRUE;
 514                                 break;
 515                         }
 516                         parsed_args->flags |= BYTEDUMP_FLAG;
 517                         if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) {
 518                                 (void) fprintf(stderr, "%s: Error in "
 519                                     "bytedump argument\n", argv[0]);
 520                                 error = B_TRUE;
 521                                 break;
 522                         }
 523                         parsed_args->bytedump_amt = (uint32_t)recv64;
 524                         if (parsed_args->bytedump_amt != recv64) {
 525                                 (void) fprintf(stderr, "%s: Bytedump amount "
 526                                     "too large for 32 bits\n", argv[0]);
 527                                 error = B_TRUE;
 528                                 break;
 529                         }
 530                         break;
 531 
 532                 /* Verbose. */
 533                 case 'v':
 534                         parsed_args->flags |= VERBOSE_FLAG;
 535                         break;
 536 
 537                 /*
 538                  * Quiet - no errors reported as messages.
 539                  * (Status still returned by program, however.)
 540                  */
 541                 case 'q':
 542                         parsed_args->flags |= QUIET_FLAG;
 543                         break;
 544 
 545                 /* Loop. */
 546                 case 'l':
 547                         parsed_args->flags |= LOOP_FLAG;
 548                         break;
 549 
 550                 /*
 551                  * Dump characters with bytedump (-b).
 552                  * Show controller info with -i.
 553                  */
 554                 case 'c':
 555                         if (parsed_args->flags & BYTEDUMP_FLAG) {
 556                                 parsed_args->flags |= CHARDUMP_FLAG;
 557 
 558                         } else if (parsed_args->flags & INTR_FLAG) {
 559                                 parsed_args->flags |= SHOWCTLR_FLAG;
 560 
 561                         } else {
 562                                 error = B_TRUE;
 563                         }
 564                         break;
 565 
 566                 /* Continue on errors with bytedump (-b). */
 567                 case 'x':
 568                         if (!(parsed_args->flags & BYTEDUMP_FLAG)) {
 569                                 error = B_TRUE;
 570                                 break;
 571                         }
 572                         parsed_args->flags |= ERRCONT_FLAG;
 573                         break;
 574 
 575                 case 'g':
 576                         if (!(parsed_args->flags & INTR_FLAG)) {
 577                                 error = B_TRUE;
 578                                 break;
 579                         }
 580                         parsed_args->flags |= SETGRP_FLAG;
 581                         break;
 582 
 583                 /* Take -y as confirmation and don't ask (where applicable). */
 584                 case 'y':
 585                         confirm = B_TRUE;
 586                         break;
 587 
 588                 /* Option without operand. */
 589                 case ':':
 590                         switch (optopt) {
 591                         case 'p':
 592                                 /* Allow -p without bdf spec. */
 593                                 parsed_args->flags |=
 594                                     (PROBETREE_FLAG | PROBERNG_FLAG);
 595                                 break;
 596                         default:
 597                                 error = B_TRUE;
 598                                 break;
 599                         }
 600                         break;
 601 
 602                 /* Unrecognized option. */
 603                 case '?':
 604                         error = B_TRUE;
 605                         break;
 606                 }
 607         }
 608 
 609         /*
 610          * Commandline has been parsed.  Check for errors which can be checked
 611          * only after commandline parsing is complete.
 612          */
 613 
 614         if (!error) {
 615 
 616                 /* Check for values straggling at the end of the command. */
 617                 if (optind != argc) {
 618                         (void) fprintf(stderr, "%s: Unrecognized parameter "
 619                             "at the end of the command.\n", argv[0]);
 620                         print_bad_option(argv, optopt, optarg);
 621                         return (FAILURE);
 622                 }
 623 
 624                 /* No args other than nexus.  Default to probing that nexus */
 625                 if (!(parsed_args->flags &
 626                     (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS))) {
 627                         usage(argv[0]);
 628                         parsed_args->flags = 0;
 629                         return (SUCCESS);
 630                 }
 631 
 632                 /*
 633                  * Don't allow any options other than all-bus, verbose or
 634                  * quiet with probe command.  Set default probe flags if nexus
 635                  * or leaf options are not specified.
 636                  */
 637                 if (parsed_args->flags & (PROBETREE_FLAG | PROBEALL_FLAG)) {
 638                         if (parsed_args->flags &
 639                             ~(PROBE_FLAGS | QUIET_FLAG | VERBOSE_FLAG))
 640                                 error = B_TRUE;
 641                 }
 642 
 643                 /*
 644                  * Allow only read, write, quiet and verbose flags for
 645                  * interrupt command.  Note that INO_SPEC_FLAG and CPU_SPEC_FLAG
 646                  * get set for interrupt command.
 647                  */
 648                 if (parsed_args->flags & INTR_FLAG) {
 649                         if (parsed_args->flags &
 650                             ~(INTR_FLAG | VERBOSE_FLAG | QUIET_FLAG |
 651                             READ_FLAG | WRITE_FLAG | SHOWCTLR_FLAG |
 652                             SETGRP_FLAG | INO_ALL_FLAG | INO_SPEC_FLAG |
 653                             MSI_ALL_FLAG | MSI_SPEC_FLAG | CPU_SPEC_FLAG)) {
 654                                 (void) fprintf(stderr, "%s: -v, -q, -r, -w, -c "
 655                                     "-g are only options allowed with "
 656                                     "interrupt command.\n", argv[0]);
 657                                 error = B_TRUE;
 658                         }
 659 
 660                         /* Need cpu and ino values for interrupt set command. */
 661                         if ((parsed_args->flags & WRITE_FLAG) &&
 662                             !(parsed_args->flags & CPU_SPEC_FLAG) &&
 663                             !((parsed_args->flags & INO_SPEC_FLAG) ||
 664                             (parsed_args->flags & MSI_SPEC_FLAG))) {
 665                                 (void) fprintf(stderr,
 666                                     "%s: Both cpu and ino/msi must be "
 667                                     "specified explicitly for interrupt "
 668                                     "set command.\n", argv[0]);
 669                                 error = B_TRUE;
 670                         }
 671 
 672                         /* Intr write and show ctlr flags are incompatible. */
 673                         if ((parsed_args->flags &
 674                             (WRITE_FLAG + SHOWCTLR_FLAG)) ==
 675                             (WRITE_FLAG + SHOWCTLR_FLAG)) {
 676                                 (void) fprintf(stderr,
 677                                     "%s: -w and -c are incompatible for "
 678                                     "interrupt command.\n", argv[0]);
 679                                 error = B_TRUE;
 680                         }
 681 
 682                         /* Intr setgrp flag valid only for intr writes. */
 683                         if ((parsed_args->flags & (WRITE_FLAG + SETGRP_FLAG)) ==
 684                             SETGRP_FLAG) {
 685                                 (void) fprintf(stderr,
 686                                     "%s: -g is incompatible with -r "
 687                                     "for interrupt command.\n", argv[0]);
 688                                 error = B_TRUE;
 689                         }
 690 
 691                         /*
 692                          * Disallow read & write together in interrupt command.
 693                          */
 694                         if ((parsed_args->flags & (WRITE_FLAG | READ_FLAG)) ==
 695                             (WRITE_FLAG | READ_FLAG)) {
 696                                 (void) fprintf(stderr, "%s: Only one of -r and "
 697                                     "-w can be specified in "
 698                                     "interrupt command.\n", argv[0]);
 699                                 error = B_TRUE;
 700                         }
 701                 }
 702 
 703                 /* Bytedump incompatible with some other options. */
 704                 if ((parsed_args->flags & BYTEDUMP_FLAG) &&
 705                     (parsed_args->flags &
 706                     (WRITE_FLAG | PROBE_FLAGS | INTR_FLAG))) {
 707                         (void) fprintf(stderr,
 708                             "%s: -b is incompatible with "
 709                             "another specified option.\n", argv[0]);
 710                         error = B_TRUE;
 711                 }
 712 
 713                 if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) {
 714 
 715                         if (!(parsed_args->flags & SIZE_FLAG)) {
 716                                 parsed_args->size = DEFAULT_SIZE;
 717                         }
 718                         if ((parsed_args->flags & WRITE_FLAG) &&
 719                             parsed_args->size < sizeof (uint64_t) &&
 720                             (parsed_args->write_value >>
 721                             (parsed_args->size * BITS_PER_BYTE))) {
 722                                 (void) fprintf(stderr,
 723                                     "%s: Data to write is larger than "
 724                                     "specified size.\n", argv[0]);
 725                                 error = B_TRUE;
 726                         }
 727 
 728                 } else { /* Looping is compatible only with register cmds. */
 729 
 730                         if (parsed_args->flags & LOOP_FLAG) {
 731                                 (void) fprintf(stderr, "%s: -l is incompatible "
 732                                     "with given command.\n", argv[0]);
 733                                 error = B_TRUE;
 734                         }
 735                 }
 736 
 737                 /* Call out an erroneous -y and then ignore it. */
 738                 if ((confirm) && (!(parsed_args->flags & BASE_SPEC_FLAG))) {
 739                                 (void) fprintf(stderr,
 740                                     "%s: -y is incompatible with given command."
 741                                     "  Ignoring.\n", argv[0]);
 742                 }
 743         }
 744 
 745         /* Now fill in the defaults and other holes. */
 746         if (!(error)) {
 747                 if (!(parsed_args->flags & (READ_FLAG | WRITE_FLAG))) {
 748                         parsed_args->flags |= READ_FLAG;
 749                 }
 750 
 751                 if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) {
 752                         if (!(parsed_args->flags & ENDIAN_FLAG)) {
 753                                 parsed_args->big_endian = B_FALSE;
 754                         }
 755                 }
 756 
 757                 if (parsed_args->flags & BASE_SPEC_FLAG) {
 758                         if (!confirm) {
 759                                 confirm = get_confirmation();
 760                         }
 761                         if (!confirm) {
 762                                 parsed_args->flags &= ~ALL_COMMANDS;
 763                         }
 764                 }
 765 
 766                 /*
 767                  * As far as other defaults are concerned:
 768                  *   Other fields: bus, device, function, offset, default to
 769                  *   zero.
 770                  */
 771 
 772         } else {        /* An error occurred. */
 773 
 774                 print_bad_option(argv, optopt, optarg);
 775         }
 776         return (error);
 777 }
 778 
 779 
 780 /* Module-private functions. */
 781 
 782 static void
 783 print_bad_option(char *argv[], int optopt, char *optarg)
 784 {
 785         /* Illegal option operand */
 786         if (optarg != NULL) {
 787                 (void) fprintf(stderr,
 788                     "%s: illegal operand %s specified for option %c\n",
 789                     argv[0], optarg, optopt);
 790 
 791         /* Illegal option */
 792         } else if (optopt != 0) {
 793                 (void) fprintf(stderr,
 794                     "%s: option %c is illegal or is missing an operand\n",
 795                     argv[0], optopt);
 796 
 797         /* getopt wasn't even called.  Bad device spec. */
 798         } else {
 799                 (void) fprintf(stderr,
 800                     "%s: device spec must start with %s or %s...\n", argv[0],
 801                     DEVNAME_START_PCI, DEVNAME_START_NIU);
 802         }
 803 
 804         (void) fprintf(stderr,
 805             "%s: Type \"%s -h\" to get help on running this program.\n",
 806             argv[0], argv[0]);
 807 }
 808 
 809 /*
 810  * Warn the user and ask for confirmation.
 811  */
 812 static boolean_t
 813 get_confirmation()
 814 {
 815         int i, b;
 816 
 817         (void) printf("WARNING: This cmd with a bad addr can panic "
 818             "the system.  Continue [y/n] (n)? ");
 819         for (i = 0; ; i++) {
 820                 b = getchar();
 821                 switch (b) {
 822                 case ' ':
 823                 case '\t':
 824                         break;
 825                 case 'y':
 826                 case 'Y':
 827                         return (B_TRUE);
 828                 default:
 829                         return (B_FALSE);
 830                 }
 831         }
 832 }
 833 
 834 
 835 /*
 836  * Given a digit string, return a 64 bit value.
 837  *
 838  * If the hex_only arg is true, interpret all strings as hex.
 839  * Otherwise, interpret as strtoull(3C) does with base=0.
 840  */
 841 static int
 842 get_value64(char *value_str, uint64_t *value, boolean_t hex_only)
 843 {
 844 
 845         /* This is overkill for now, as everything is in hex. */
 846         static char dec_digits[] = "0123456789";
 847         static char hex_digits[] = "01234567890abcdefABCDEF";
 848         static char oct_digits[] = "01234567";
 849 
 850         char *digit_string;
 851         char *string_to_check;
 852 
 853         if ((value_str == NULL) || (strlen(value_str) == 0)) {
 854                 (void) fprintf(stderr, "Missing value argument.\n");
 855                 return (FAILURE);
 856         }
 857 
 858         if (!hex_only && (value_str[0] != '0')) {
 859                 digit_string = dec_digits;
 860                 string_to_check = value_str;
 861         } else if ((value_str[1] == 'X') || (value_str[1] == 'x')) {
 862                 digit_string = hex_digits;
 863                 string_to_check = &value_str[2];    /* Ignore 0x of hex */
 864         } else if (hex_only) {
 865                 digit_string = hex_digits;
 866                 string_to_check = value_str;    /* Hex number, no 0x prefix */
 867         } else {
 868                 digit_string = oct_digits;
 869                 string_to_check = value_str;
 870         }
 871 
 872         /*
 873          * Verify value is all proper digits.
 874          *
 875          * For some reason, strtoull doesn't return an error when it cannot
 876          * interpret the value.  This is why we do the checking ourselves.
 877          */
 878         if (strspn(string_to_check, digit_string) != strlen(string_to_check)) {
 879                 (void) fprintf(stderr,
 880                     "Value must contain only valid digits.\n");
 881                 return (FAILURE);
 882         }
 883 
 884         *value = strtoull(value_str, NULL, (hex_only ? 16 : 0));
 885 
 886         return (SUCCESS);
 887 }
 888 
 889 
 890 /*
 891  * Parse nexus options.  This includes:
 892  *   bank=number
 893  *
 894  * input is what the user specified for the options on the commandline,
 895  * flags_arg is modified with the option set, and bank_arg returns the value
 896  * specified for bank.
 897  */
 898 static int
 899 parse_nexus_opts(char *input, uint64_t *flags_arg, uint8_t *bank_arg,
 900     uint64_t *base_addr_arg)
 901 {
 902         enum nexus_opts_index {
 903                 bank = 0,
 904                 base
 905         };
 906 
 907         static char *nexus_opts[] = {
 908                 "bank",
 909                 "base",
 910                 NULL
 911         };
 912 
 913         char *value;
 914         uint64_t        recv64;
 915 
 916         int rval = SUCCESS;
 917 
 918         if (input == NULL) {
 919                 (void) fprintf(stderr, "Missing argument.\n");
 920                 return (FAILURE);
 921         }
 922 
 923         while ((*input != '\0') && (rval == SUCCESS)) {
 924                 switch (getsubopt(&input, nexus_opts, &value)) {
 925                 case bank:
 926                         if (*flags_arg & BANK_SPEC_FLAG) {
 927                                 (void) fprintf(stderr, "The bank or bar arg is "
 928                                     "specified more than once.\n");
 929                                 rval = FAILURE;
 930                                 break;
 931                         }
 932                         if (*flags_arg & BASE_SPEC_FLAG) {
 933                                 (void) fprintf(stderr, "Bank and base address "
 934                                     "cannot both be specified.\n");
 935                                 rval = FAILURE;
 936                                 break;
 937                         }
 938                         if (value == NULL) {
 939                                 (void) fprintf(stderr, "Missing bank value.\n");
 940                                 rval = FAILURE;
 941                                 break;
 942                         }
 943                         if ((rval = get_value64(value, &recv64, HEX_ONLY)) !=
 944                             SUCCESS) {
 945                                 break;
 946                         }
 947                         *bank_arg = (uint8_t)recv64;
 948                         if (*bank_arg != recv64) {
 949                                 (void) fprintf(stderr,
 950                                     "Bank argument must fit into 8 bits.\n");
 951                                 rval = FAILURE;
 952                                 break;
 953                         }
 954                         *flags_arg |= BANK_SPEC_FLAG;
 955                         break;
 956 
 957                 case base:
 958                         if (*flags_arg & BASE_SPEC_FLAG) {
 959                                 (void) fprintf(stderr, "The base address "
 960                                     "is specified more than once.\n");
 961                                 rval = FAILURE;
 962                                 break;
 963                         }
 964                         if (*flags_arg & BANK_SPEC_FLAG) {
 965                                 (void) fprintf(stderr, "Bank and base address "
 966                                     "cannot both be specified.\n");
 967                                 rval = FAILURE;
 968                                 break;
 969                         }
 970                         if (value == NULL) {
 971                                 (void) fprintf(stderr,
 972                                     "Missing base addr value.\n");
 973                                 rval = FAILURE;
 974                                 break;
 975                         }
 976                         if ((rval = get_value64(value, base_addr_arg,
 977                             HEX_ONLY)) != SUCCESS) {
 978                                 break;
 979                         }
 980                         *flags_arg |= BASE_SPEC_FLAG;
 981                         break;
 982 
 983                 default:
 984                         (void) fprintf(stderr, "Unrecognized option for -n\n");
 985                         rval = FAILURE;
 986                         break;
 987                 }
 988         }
 989 
 990         return (rval);
 991 }
 992 
 993 
 994 static int
 995 extract_bdf_arg(char *cvalue, char *fld, uint64_t fld_flag, uint64_t *all_flags,
 996     uint8_t *ivalue)
 997 {
 998         uint64_t recv64;
 999 
1000         if (*all_flags & fld_flag) {
1001                 (void) fprintf(stderr,
1002                     "The %s is specified more than once.\n", fld);
1003                 return (FAILURE);
1004         }
1005         if (get_value64(cvalue, &recv64, HEX_ONLY) != SUCCESS)
1006                 return (FAILURE);
1007 
1008         *ivalue = (uint8_t)recv64;
1009         if (recv64 != *ivalue) {
1010                 (void) fprintf(stderr,
1011                     "This program limits the %s argument to 8 bits.\n", fld);
1012                 (void) fprintf(stderr, "The actual maximum may be "
1013                     "smaller but cannot be enforced by this program.\n");
1014                 return (FAILURE);
1015         }
1016 
1017         *all_flags |= fld_flag;
1018         return (SUCCESS);
1019 }
1020 
1021 
1022 static int extract_bdf(char *value, char **bvalue_p, char **dvalue_p,
1023     char **fvalue_p)
1024 {
1025         char *strtok_state;
1026         char *dummy;
1027         static char *separator = ".";
1028 
1029         *bvalue_p = strtok_r(value, separator, &strtok_state);
1030         *dvalue_p = strtok_r(NULL, separator, &strtok_state);
1031         *fvalue_p = strtok_r(NULL, separator, &strtok_state);
1032         dummy = strtok_r(NULL, separator, &strtok_state);
1033 
1034         /* Return failure only if too many values specified. */
1035         return ((dummy) ? FAILURE : SUCCESS);
1036 }
1037 
1038 /*
1039  * Parse device options.  This includes:
1040  *   bus=number
1041  *   dev=number
1042  *   func=number
1043  *   bank=number
1044  *   config
1045  *   bar0
1046  *   bar1
1047  *   bar2
1048  *   bar3
1049  *   bar4
1050  *   bar5
1051  *   rom
1052  *
1053  * input is what the user specified for the options on the commandline,
1054  * flags_arg is modified with the options set, and the rest of the args return
1055  * their respective values.
1056  */
1057 static int
1058 parse_device_opts(
1059     char *input, uint64_t *flags_arg, uint8_t *bus_arg, uint8_t *device_arg,
1060     uint8_t *func_arg, uint8_t *bank_arg)
1061 {
1062         /* Needed by getsubopt(3C) */
1063         enum bdf_opts_index {
1064                 bus = 0,
1065                 dev = 1,
1066                 func = 2,
1067                 bdf = 3,
1068                 bank = 4,
1069                 config = 5,
1070                 bar0 = 6,
1071                 bar1 = 7,
1072                 bar2 = 8,
1073                 bar3 = 9,
1074                 bar4 = 10,
1075                 bar5 = 11,
1076                 rom = 12
1077         };
1078 
1079         /* Needed by getsubopt(3C) */
1080         static char *bdf_opts[] = {
1081                 "bus",
1082                 "dev",
1083                 "func",
1084                 "bdf",
1085                 "bank",
1086                 "config",
1087                 "bar0",
1088                 "bar1",
1089                 "bar2",
1090                 "bar3",
1091                 "bar4",
1092                 "bar5",
1093                 "rom",
1094                 NULL };
1095 
1096         char *value;            /* Current suboption being processed. */
1097         uint64_t recv64;        /* Temporary value. */
1098 
1099         /* This error message is used in many places. */
1100         static char bank_err[] =
1101             {"The bank or bar arg is specified more than once.\n"};
1102 
1103         int rval = SUCCESS;
1104 
1105         while ((*input != '\0') && (rval == SUCCESS)) {
1106                 switch (getsubopt(&input, bdf_opts, &value)) {
1107 
1108                 /* bus=number */
1109                 case bdf: {
1110                         char *bvalue, *dvalue, *fvalue;
1111 
1112                         if ((rval = extract_bdf(value, &bvalue, &dvalue,
1113                             &fvalue)) != SUCCESS) {
1114                                 break;
1115                         }
1116 
1117                         if (!bvalue | !dvalue | !fvalue) {
1118                                 break;
1119                         }
1120 
1121                         if ((rval = extract_bdf_arg(bvalue, "bus",
1122                             BUS_SPEC_FLAG, flags_arg, bus_arg)) != SUCCESS) {
1123                                 break;
1124                         }
1125                         if ((rval = extract_bdf_arg(dvalue, "dev",
1126                             DEV_SPEC_FLAG, flags_arg, device_arg)) != SUCCESS) {
1127                                 break;
1128                         }
1129                         rval = extract_bdf_arg(fvalue, "func",
1130                             FUNC_SPEC_FLAG, flags_arg, func_arg);
1131                         break;
1132                 }
1133 
1134                 case bus:
1135                         rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG,
1136                             flags_arg, bus_arg);
1137                         break;
1138 
1139                 /* dev=number */
1140                 case dev:
1141                         rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG,
1142                             flags_arg, device_arg);
1143                         break;
1144 
1145                 /* func=number */
1146                 case func:
1147                         rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG,
1148                             flags_arg, func_arg);
1149                         break;
1150 
1151                 /* bank=number */
1152                 case bank:
1153                         if (*flags_arg & BANK_SPEC_FLAG) {
1154                                 (void) fprintf(stderr, bank_err);
1155                                 rval = FAILURE;
1156                                 break;
1157                         }
1158                         if ((rval = get_value64(value, &recv64, HEX_ONLY)) !=
1159                             SUCCESS) {
1160                                 break;
1161                         }
1162                         *bank_arg = (uint8_t)recv64;
1163                         if (rval || (*bank_arg != recv64)) {
1164                                 (void) fprintf(stderr, "Bank argument must"
1165                                     " fit into 8 bits.\n");
1166                                 rval = FAILURE;
1167                                 break;
1168                         }
1169                         *flags_arg |= BANK_SPEC_FLAG;
1170                         break;
1171 
1172                 /* config */
1173                 case config:
1174                         if (*flags_arg & BANK_SPEC_FLAG) {
1175                                 (void) fprintf(stderr, bank_err);
1176                                 rval = FAILURE;
1177                                 break;
1178                         }
1179                         *bank_arg = PCITOOL_CONFIG;
1180                         *flags_arg |= BANK_SPEC_FLAG;
1181                         break;
1182 
1183                 /* bar0 */
1184                 case bar0:
1185                         if (*flags_arg & BANK_SPEC_FLAG) {
1186                                 (void) fprintf(stderr, bank_err);
1187                                 rval = FAILURE;
1188                                 break;
1189                         }
1190                         *bank_arg = PCITOOL_BAR0;
1191                         *flags_arg |= BANK_SPEC_FLAG;
1192                         break;
1193 
1194                 /* bar1 */
1195                 case bar1:
1196                         if (*flags_arg & BANK_SPEC_FLAG) {
1197                                 (void) fprintf(stderr, bank_err);
1198                                 rval = FAILURE;
1199                                 break;
1200                         }
1201                         *bank_arg = PCITOOL_BAR1;
1202                         *flags_arg |= BANK_SPEC_FLAG;
1203                         break;
1204 
1205                 /* bar2 */
1206                 case bar2:
1207                         if (*flags_arg & BANK_SPEC_FLAG) {
1208                                 (void) fprintf(stderr, bank_err);
1209                                 rval = FAILURE;
1210                                 break;
1211                         }
1212                         *bank_arg = PCITOOL_BAR2;
1213                         *flags_arg |= BANK_SPEC_FLAG;
1214                         break;
1215 
1216                 /* bar3 */
1217                 case bar3:
1218                         if (*flags_arg & BANK_SPEC_FLAG) {
1219                                 (void) fprintf(stderr, bank_err);
1220                                 rval = FAILURE;
1221                                 break;
1222                         }
1223                         *bank_arg = PCITOOL_BAR3;
1224                         *flags_arg |= BANK_SPEC_FLAG;
1225                         break;
1226 
1227                 /* bar4 */
1228                 case bar4:
1229                         if (*flags_arg & BANK_SPEC_FLAG) {
1230                                 (void) fprintf(stderr, bank_err);
1231                                 rval = FAILURE;
1232                                 break;
1233                         }
1234                         *bank_arg = PCITOOL_BAR4;
1235                         *flags_arg |= BANK_SPEC_FLAG;
1236                         break;
1237 
1238                 /* bar5 */
1239                 case bar5:
1240                         if (*flags_arg & BANK_SPEC_FLAG) {
1241                                 (void) fprintf(stderr, bank_err);
1242                                 rval = FAILURE;
1243                                 break;
1244                         }
1245                         *bank_arg = PCITOOL_BAR5;
1246                         *flags_arg |= BANK_SPEC_FLAG;
1247                         break;
1248 
1249                 /* rom */
1250                 case rom:
1251                         if (*flags_arg & BANK_SPEC_FLAG) {
1252                                 (void) fprintf(stderr, bank_err);
1253                                 rval = FAILURE;
1254                                 break;
1255                         }
1256                         *bank_arg = PCITOOL_ROM;
1257                         *flags_arg |= BANK_SPEC_FLAG;
1258                         break;
1259 
1260                 default:
1261                         (void) fprintf(stderr, "Unrecognized option for -d\n");
1262                         rval = FAILURE;
1263                         break;
1264                 }
1265         }
1266 
1267         /* Bus, dev and func must all be specified. */
1268         if ((*flags_arg & (BUS_SPEC_FLAG | DEV_SPEC_FLAG | FUNC_SPEC_FLAG)) !=
1269             (BUS_SPEC_FLAG | DEV_SPEC_FLAG | FUNC_SPEC_FLAG)) {
1270                 rval = FAILURE;
1271 
1272         /* No bank specified in any way.  Default to config space */
1273         } else if ((*flags_arg & BANK_SPEC_FLAG) == 0) {
1274                 *flags_arg |= BANK_SPEC_FLAG;
1275                 *bank_arg = PCITOOL_CONFIG;
1276         }
1277 
1278         return (rval);
1279 }
1280 
1281 
1282 /*
1283  * Parse INO options.  This includes:
1284  *   ino#  | all
1285  *
1286  * input is the string of options to parse.  flags_arg returns modified with
1287  * specified options set.  Other args return their respective values.
1288  */
1289 static int
1290 parse_ino_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg,
1291     uint8_t *ino_arg)
1292 {
1293         uint64_t        value;
1294         char            *charvalue;
1295         int             rval = SUCCESS;
1296 
1297         if (strcmp(input, "all") == 0) {
1298                 *flags_arg |= INO_ALL_FLAG;
1299 #ifdef __x86
1300         } else if (strstr(input, ",") == NULL) {
1301                 (void) fprintf(stderr,
1302                     "Interrupt format should be <cpu#,ino#>.\n");
1303                 rval = FAILURE;
1304 #else
1305         } else if (strstr(input, ",") == NULL) {
1306                 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1307                         *ino_arg = (uint8_t)value;
1308 
1309                 if (*ino_arg != value) {
1310                         (void) fprintf(stderr,
1311                             "ino argument must fit into 8 bits.\n");
1312                         rval = FAILURE;
1313                 } else {
1314                         *flags_arg |= INO_SPEC_FLAG;
1315                 }
1316 #endif
1317         } else if (charvalue = strtok(input, ",")) {
1318                 if ((rval =
1319                     get_value64(charvalue, &value, HEX_ONLY)) == SUCCESS) {
1320                         *cpu_arg = (int)value;
1321                 }
1322 
1323                 input = strtok(NULL, ",");
1324                 if (input == NULL) {
1325                         (void) fprintf(stderr, "ino argument is need.\n");
1326                         return (FAILURE);
1327                 }
1328 
1329                 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1330                         *ino_arg = (uint8_t)value;
1331 
1332                 if (*ino_arg != value) {
1333                         (void) fprintf(stderr,
1334                             "ino argument must fit into 8 bits.\n");
1335                         rval = FAILURE;
1336                 } else {
1337                         *flags_arg |= INO_SPEC_FLAG;
1338                 }
1339         } else {
1340                 (void) fprintf(stderr,
1341                     "Unrecognized option for -i\n");
1342                 rval = FAILURE;
1343         }
1344 
1345         return (rval);
1346 }
1347 
1348 
1349 /*
1350  * Parse MSI options.  This includes:
1351  *   msi#  | all
1352  *
1353  * input is the string of options to parse.  flags_arg returns modified with
1354  * specified options set.  Other args return their respective values.
1355  */
1356 static int
1357 parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg)
1358 {
1359         uint64_t        value;
1360         int             rval = SUCCESS;
1361 
1362         if (strcmp(input, "all") == 0) {
1363                 *flags_arg |= MSI_ALL_FLAG;
1364         } else if (strstr(input, ",") == NULL) {
1365                 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1366                         *msi_arg = (uint16_t)value;
1367 
1368                 if (*msi_arg != value) {
1369                         (void) fprintf(stderr,
1370                             "msi argument must fit into 16 bits.\n");
1371                         rval = FAILURE;
1372                 } else {
1373                         *flags_arg |= MSI_SPEC_FLAG;
1374                 }
1375         } else if (strtok(input, ",")) {
1376                 input = strtok(NULL, ",");
1377                 if (input == NULL) {
1378                         (void) fprintf(stderr, "msi argument is need.\n");
1379                         return (FAILURE);
1380                 }
1381 
1382                 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1383                         *msi_arg = (uint16_t)value;
1384 
1385                 if (*msi_arg != value) {
1386                         (void) fprintf(stderr,
1387                             "msi argument must fit into 16 bits.\n");
1388                         rval = FAILURE;
1389                 } else {
1390                         *flags_arg |= MSI_SPEC_FLAG;
1391                 }
1392         } else {
1393                 (void) fprintf(stderr,
1394                     "Unrecognized option for -m\n");
1395                 rval = FAILURE;
1396         }
1397 
1398         return (rval);
1399 }
1400 
1401 
1402 /*
1403  * Parse interrupt set options.  This includes:
1404  *   cpu=number
1405  *
1406  * input is the string of options to parse.  flags_arg returns modified with
1407  * specified options set.  Other args return their respective values.
1408  */
1409 static int
1410 parse_intr_set_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg)
1411 {
1412         uint64_t        value;
1413         int             rval = SUCCESS;
1414 
1415         if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS) {
1416 
1417                 if ((long)value > sysconf(_SC_CPUID_MAX)) {
1418                         (void) fprintf(stderr, "Cpu argument "
1419                             "exceeds maximum for this system type.\n");
1420                         rval = FAILURE;
1421                 } else {
1422                         *cpu_arg = (uint32_t)value;
1423                         *flags_arg |= CPU_SPEC_FLAG;
1424                 }
1425         } else {
1426                 (void) fprintf(stderr,
1427                     "Unrecognized option for -i -m -w\n");
1428                 rval = FAILURE;
1429         }
1430 
1431         return (rval);
1432 }
1433 
1434 
1435 static int
1436 parse_probeone_opts(
1437     char *input, uint64_t *flags_arg, uint8_t *bus_arg, uint8_t *device_arg,
1438     uint8_t *func_arg)
1439 {
1440         enum p1_bdf_opts_index {
1441                 bus = 0,
1442                 dev = 1,
1443                 func = 2,
1444                 bdf = 3
1445         };
1446 
1447         /* Needed by getsubopt(3C) */
1448         static char *p1_bdf_opts[] = {
1449                 "bus",
1450                 "dev",
1451                 "func",
1452                 "bdf",
1453                 NULL };
1454 
1455         char *value;            /* Current suboption being processed. */
1456 
1457         int rval = SUCCESS;
1458 
1459         while ((*input != '\0') && (rval == SUCCESS)) {
1460                 switch (getsubopt(&input, p1_bdf_opts, &value)) {
1461 
1462                 /* bus=number */
1463                 case bdf: {
1464                         char *bvalue, *dvalue, *fvalue;
1465 
1466                         if ((rval = extract_bdf(value, &bvalue, &dvalue,
1467                             &fvalue)) != SUCCESS) {
1468                                 break;
1469                         }
1470                         if (bvalue)
1471                                 if ((rval = extract_bdf_arg(bvalue, "bus",
1472                                     BUS_SPEC_FLAG, flags_arg, bus_arg)) !=
1473                                     SUCCESS) {
1474                                         break;
1475                                 }
1476                         if (dvalue)
1477                                 if ((rval = extract_bdf_arg(dvalue, "dev",
1478                                     DEV_SPEC_FLAG, flags_arg, device_arg)) !=
1479                                     SUCCESS) {
1480                                 break;
1481                         }
1482                         if (fvalue)
1483                                 rval = extract_bdf_arg(fvalue, "func",
1484                                     FUNC_SPEC_FLAG, flags_arg, func_arg);
1485                         break;
1486                 }
1487 
1488                 case bus:
1489                         rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG,
1490                             flags_arg, bus_arg);
1491                         break;
1492 
1493                 /* dev=number */
1494                 case dev:
1495                         rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG,
1496                             flags_arg, device_arg);
1497                         break;
1498 
1499                 /* func=number */
1500                 case func:
1501                         rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG,
1502                             flags_arg, func_arg);
1503                         break;
1504 
1505                 default:
1506                         (void) fprintf(stderr, "Unrecognized option for -p\n");
1507                         rval = FAILURE;
1508                         break;
1509                 }
1510         }
1511 
1512         return (rval);
1513 }
1514 
1515 
1516 #ifdef DEBUG
1517 
1518 static void
1519 dump_struct(pcitool_uiargs_t *dumpthis)
1520 {
1521         (void) printf("flags:0x%x\n", dumpthis->flags);
1522         (void) printf("bus:%d (0x%x)\n",
1523             dumpthis->bus, dumpthis->bus);
1524         (void) printf("device:%d (0x%x)\n", dumpthis->device,
1525             dumpthis->device);
1526         (void) printf("function:%d (0x%x)\n", dumpthis->function,
1527             dumpthis->function);
1528         (void) printf("write_value:%" PRIu64 " (0x%" PRIx64 ")\n",
1529             dumpthis->write_value, dumpthis->write_value);
1530         (void) printf("bank:%d (0x%x)\n",
1531             dumpthis->bank, dumpthis->bank);
1532         (void) printf("offset:%d (0x%x)\n", dumpthis->offset, dumpthis->offset);
1533         (void) printf("size:%d, endian:%s\n", dumpthis->size,
1534             dumpthis->big_endian ? "BIG" : "little");
1535         (void) printf("ino:%d, cpu:%d\n",
1536             dumpthis->intr_ino, dumpthis->intr_cpu);
1537 }
1538 
1539 #ifdef STANDALONE
1540 
1541 /* Test program for this module.  Useful when implementing new options. */
1542 int
1543 main(int argc, char *argv[])
1544 {
1545         int status;
1546         pcitool_uiargs_t parsed_args;
1547 
1548         status = get_commandline_args(argc, argv, &parsed_args);
1549         if (status) {
1550                 (void) printf("Error getting command.\n");
1551         }
1552         dump_struct(&parsed_args);
1553 
1554         return (SUCCESS);
1555 }
1556 
1557 #endif  /* STANDALONE */
1558 #endif  /* DEBUG */