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