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