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