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 2010 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 "/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, uint8_t *ino_arg); 90 static int parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg); 91 static int parse_intr_set_opts(char *input, uint64_t *flags_arg, 92 uint32_t *cpu_arg); 93 static int parse_probeone_opts(char *input, uint64_t *flags_arg, 94 uint8_t *bus_arg, uint8_t *device_arg, uint8_t *func_arg); 95 96 #ifdef DEBUG 97 void dump_struct(pcitool_uiargs_t *dump_this); 98 #endif 99 100 /* Exported functions. */ 101 102 /* 103 * Main commandline argument parsing routine. 104 * 105 * Takes argc and argv straight from the commandline. 106 * Returns a pcitool_uiargs_t with flags of options specified, and values 107 * associated with them. 108 */ 109 int 110 get_commandline_args(int argc, char *argv[], pcitool_uiargs_t *parsed_args) 111 { 112 int c; /* Current option being processed. */ 113 boolean_t error = B_FALSE; 114 boolean_t confirm = B_FALSE; 115 uint64_t recv64; 116 117 /* Needed for getopt(3C) */ 118 extern char *optarg; /* Current commandline string. */ 119 extern int optind; /* Index of current commandline string. */ 120 extern int optopt; /* Option (char) which is missing an operand. */ 121 extern int opterr; /* Set to 0 to disable getopt err reporting. */ 122 123 opterr = 0; 124 125 bzero(parsed_args, sizeof (pcitool_uiargs_t)); 126 127 /* No args. probe mode accounting for bus ranges, nonverbose. */ 128 if (argc == 1) { 129 usage(argv[0]); 130 parsed_args->flags = 0; 131 return (SUCCESS); 132 } 133 134 /* 1st arg is not a device name. */ 135 if ((strstr(argv[1], DEVNAME_START_PCI) != argv[1]) && 136 (strstr(argv[1], DEVNAME_START_NIU) != 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 print_bad_option(argv, optopt, optarg); 191 return (FAILURE); 192 } 193 194 return (SUCCESS); 195 } 196 197 /* Device node specified on commandline. */ 198 199 /* Skip argv[1] before continuing below. */ 200 optind++; 201 202 /* Loop through the options until complete or an error is found. */ 203 while (((c = getopt(argc, argv, opt_string)) != -1) && 204 (error == B_FALSE)) { 205 206 switch (c) { 207 208 /* Nexus */ 209 case 'n': 210 if (parsed_args->flags & (LEAF_FLAG | 211 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) { 212 (void) fprintf(stderr, "%s: -n set with " 213 "-d, -p or -i or is set twice\n", argv[0]); 214 error = B_TRUE; 215 break; 216 } 217 parsed_args->flags |= NEXUS_FLAG; 218 if (parse_nexus_opts(optarg, &parsed_args->flags, 219 &parsed_args->bank, &parsed_args->base_address) != 220 SUCCESS) { 221 (void) fprintf(stderr, 222 "%s: Error parsing -n options\n", argv[0]); 223 error = B_TRUE; 224 break; 225 } 226 break; 227 228 /* Device (leaf node) */ 229 case 'd': 230 if (parsed_args->flags & (LEAF_FLAG | 231 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) { 232 (void) fprintf(stderr, "%s: -d set with " 233 "-n, -p or -i or is set twice\n", argv[0]); 234 error = B_TRUE; 235 break; 236 } 237 parsed_args->flags |= LEAF_FLAG; 238 if (parse_device_opts(optarg, &parsed_args->flags, 239 &parsed_args->bus, &parsed_args->device, 240 &parsed_args->function, 241 &parsed_args->bank) != SUCCESS) { 242 (void) fprintf(stderr, 243 "%s: Error parsing -d options\n", argv[0]); 244 error = B_TRUE; 245 break; 246 } 247 break; 248 249 /* Interrupt */ 250 case 'i': 251 if (parsed_args->flags & (LEAF_FLAG | 252 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) { 253 (void) fprintf(stderr, "%s: -i set with -m, " 254 "-n, -d or -p or is set twice\n", argv[0]); 255 error = B_TRUE; 256 break; 257 } 258 parsed_args->flags |= INTR_FLAG; 259 260 /* parse input to get ino value. */ 261 if (parse_ino_opts(optarg, &parsed_args->flags, 262 &parsed_args->intr_ino) != SUCCESS) { 263 (void) fprintf(stderr, 264 "%s: Error parsing interrupt options\n", 265 argv[0]); 266 error = B_TRUE; 267 } 268 break; 269 /* Interrupt */ 270 case 'm': 271 if (parsed_args->flags & (LEAF_FLAG | 272 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) { 273 (void) fprintf(stderr, "%s: -m set with -i, " 274 "-n, -d or -p or is set twice\n", argv[0]); 275 error = B_TRUE; 276 break; 277 } 278 parsed_args->flags |= INTR_FLAG; 279 280 /* parse input to get msi value. */ 281 if (parse_msi_opts(optarg, &parsed_args->flags, 282 &parsed_args->intr_msi) != SUCCESS) { 283 (void) fprintf(stderr, 284 "%s: Error parsing interrupt options\n", 285 argv[0]); 286 error = B_TRUE; 287 } 288 break; 289 /* Probe */ 290 case 'p': 291 if (parsed_args->flags & (LEAF_FLAG | 292 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) { 293 (void) fprintf(stderr, "%s: -p set with " 294 "-n, -d or -i or is set twice\n", argv[0]); 295 error = B_TRUE; 296 break; 297 } 298 299 /* Process -p with no dedicated options to it. */ 300 if (optarg[0] == '-') { 301 optind--; 302 303 /* Probe given tree observing ranges */ 304 parsed_args->flags |= 305 (PROBETREE_FLAG | PROBERNG_FLAG); 306 continue; 307 } 308 309 /* parse input to get ino value. */ 310 if (parse_probeone_opts(optarg, &parsed_args->flags, 311 &parsed_args->bus, &parsed_args->device, 312 &parsed_args->function) != SUCCESS) { 313 (void) fprintf(stderr, 314 "%s: Error parsing probe options\n", 315 argv[0]); 316 error = B_TRUE; 317 } else { 318 /* 319 * parse_probeone_opts found options to 320 * set up bdf. 321 */ 322 parsed_args->flags |= PROBEDEV_FLAG; 323 } 324 break; 325 326 /* Probe all busses */ 327 case 'a': 328 /* Must follow -p, and -p must have no bdf. */ 329 if (!(parsed_args->flags & PROBETREE_FLAG)) { 330 error = B_TRUE; 331 break; 332 } 333 334 parsed_args->flags &= ~PROBERNG_FLAG; 335 break; 336 337 /* Read */ 338 case 'r': 339 if (!(parsed_args->flags & 340 (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) { 341 error = B_TRUE; 342 break; 343 } 344 345 /* 346 * Allow read and write to be set together for now, 347 * since this means write then read back for device and 348 * nexus accesses. Check for this and disallow with 349 * interrupt command later. 350 */ 351 parsed_args->flags |= READ_FLAG; 352 break; 353 354 /* Write */ 355 case 'w': 356 if (!(parsed_args->flags & 357 (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) { 358 error = B_TRUE; 359 break; 360 } 361 if (parsed_args->flags & WRITE_FLAG) { 362 (void) fprintf(stderr, "%s: -w set twice\n", 363 argv[0]); 364 error = B_TRUE; 365 break; 366 } 367 368 /* 369 * For device and nexus, get a single register value 370 * to write. 371 */ 372 if (parsed_args->flags & (NEXUS_FLAG | LEAF_FLAG)) { 373 parsed_args->flags |= WRITE_FLAG; 374 if (get_value64(optarg, 375 &parsed_args->write_value, HEX_ONLY) != 376 SUCCESS) { 377 (void) fprintf(stderr, 378 "%s: Error reading value to " 379 "write.\n", argv[0]); 380 error = B_TRUE; 381 break; 382 } 383 384 /* For interrupt, parse input to get cpu value. */ 385 } else if (parsed_args->flags & INTR_FLAG) { 386 parsed_args->flags |= WRITE_FLAG; 387 if (parse_intr_set_opts(optarg, 388 &parsed_args->flags, 389 &parsed_args->intr_cpu) != SUCCESS) { 390 (void) fprintf(stderr, "%s: Error " 391 "parsing interrupt options.\n", 392 argv[0]); 393 error = B_TRUE; 394 break; 395 } 396 397 } else { 398 error = B_TRUE; 399 break; 400 } 401 break; 402 403 /* Offset */ 404 case 'o': 405 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) { 406 error = B_TRUE; 407 break; 408 } 409 if (parsed_args->flags & OFFSET_FLAG) { 410 (void) fprintf(stderr, "%s: -o set twice\n", 411 argv[0]); 412 error = B_TRUE; 413 break; 414 } 415 parsed_args->flags |= OFFSET_FLAG; 416 if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) { 417 (void) fprintf(stderr, 418 "%s: Error in offset argument\n", argv[0]); 419 error = B_TRUE; 420 break; 421 } 422 parsed_args->offset = (uint32_t)recv64; 423 if (parsed_args->offset != recv64) { 424 (void) fprintf(stderr, "%s: Offset argument " 425 "too large for 32 bits\n", argv[0]); 426 error = B_TRUE; 427 break; 428 } 429 break; 430 431 /* Size */ 432 case 's': 433 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) { 434 error = B_TRUE; 435 break; 436 } 437 if (parsed_args->flags & SIZE_FLAG) { 438 (void) fprintf(stderr, "%s: -s set twice\n", 439 argv[0]); 440 error = B_TRUE; 441 break; 442 } 443 parsed_args->flags |= SIZE_FLAG; 444 if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) { 445 (void) fprintf(stderr, 446 "%s: Error in size argument\n", argv[0]); 447 error = B_TRUE; 448 break; 449 } 450 switch (recv64) { 451 case 1: 452 case 2: 453 case 4: 454 case 8: 455 break; 456 default: 457 error = B_TRUE; 458 (void) fprintf(stderr, 459 "%s: Error in size argument\n", argv[0]); 460 break; 461 } 462 parsed_args->size |= (uint8_t)recv64; 463 break; 464 465 /* Endian. */ 466 case 'e': 467 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) { 468 error = B_TRUE; 469 break; 470 } 471 if (parsed_args->flags & ENDIAN_FLAG) { 472 (void) fprintf(stderr, "%s: -e set twice\n", 473 argv[0]); 474 error = B_TRUE; 475 break; 476 } 477 parsed_args->flags |= ENDIAN_FLAG; 478 479 /* Only a single character allowed. */ 480 if (optarg[1] != '\0') { 481 (void) fprintf(stderr, 482 "%s: Error in endian argument\n", argv[0]); 483 error = B_TRUE; 484 break; 485 } 486 487 switch (optarg[0]) { 488 case 'b': 489 parsed_args->big_endian = B_TRUE; 490 break; 491 case 'l': 492 break; 493 default: 494 (void) fprintf(stderr, 495 "%s: Error in endian argument\n", argv[0]); 496 error = B_TRUE; 497 break; 498 } 499 break; 500 501 /* (Byte)dump */ 502 case 'b': 503 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) { 504 error = B_TRUE; 505 break; 506 } 507 if (parsed_args->flags & BYTEDUMP_FLAG) { 508 (void) fprintf(stderr, "%s: -b set twice\n", 509 argv[0]); 510 error = B_TRUE; 511 break; 512 } 513 parsed_args->flags |= BYTEDUMP_FLAG; 514 if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) { 515 (void) fprintf(stderr, "%s: Error in " 516 "bytedump argument\n", argv[0]); 517 error = B_TRUE; 518 break; 519 } 520 parsed_args->bytedump_amt = (uint32_t)recv64; 521 if (parsed_args->bytedump_amt != recv64) { 522 (void) fprintf(stderr, "%s: Bytedump amount " 523 "too large for 32 bits\n", argv[0]); 524 error = B_TRUE; 525 break; 526 } 527 break; 528 529 /* Verbose. */ 530 case 'v': 531 parsed_args->flags |= VERBOSE_FLAG; 532 break; 533 534 /* 535 * Quiet - no errors reported as messages. 536 * (Status still returned by program, however.) 537 */ 538 case 'q': 539 parsed_args->flags |= QUIET_FLAG; 540 break; 541 542 /* Loop. */ 543 case 'l': 544 parsed_args->flags |= LOOP_FLAG; 545 break; 546 547 /* 548 * Dump characters with bytedump (-b). 549 * Show controller info with -i. 550 */ 551 case 'c': 552 if (parsed_args->flags & BYTEDUMP_FLAG) { 553 parsed_args->flags |= CHARDUMP_FLAG; 554 555 } else if (parsed_args->flags & INTR_FLAG) { 556 parsed_args->flags |= SHOWCTLR_FLAG; 557 558 } else { 559 error = B_TRUE; 560 } 561 break; 562 563 /* Continue on errors with bytedump (-b). */ 564 case 'x': 565 if (!(parsed_args->flags & BYTEDUMP_FLAG)) { 566 error = B_TRUE; 567 break; 568 } 569 parsed_args->flags |= ERRCONT_FLAG; 570 break; 571 572 case 'g': 573 if (!(parsed_args->flags & INTR_FLAG)) { 574 error = B_TRUE; 575 break; 576 } 577 parsed_args->flags |= SETGRP_FLAG; 578 break; 579 580 /* Take -y as confirmation and don't ask (where applicable). */ 581 case 'y': 582 confirm = B_TRUE; 583 break; 584 585 /* Option without operand. */ 586 case ':': 587 switch (optopt) { 588 case 'p': 589 /* Allow -p without bdf spec. */ 590 parsed_args->flags |= 591 (PROBETREE_FLAG | PROBERNG_FLAG); 592 break; 593 default: 594 error = B_TRUE; 595 break; 596 } 597 break; 598 599 /* Unrecognized option. */ 600 case '?': 601 error = B_TRUE; 602 break; 603 } 604 } 605 606 /* 607 * Commandline has been parsed. Check for errors which can be checked 608 * only after commandline parsing is complete. 609 */ 610 611 if (!error) { 612 613 /* Check for values straggling at the end of the command. */ 614 if (optind != argc) { 615 (void) fprintf(stderr, "%s: Unrecognized parameter " 616 "at the end of the command.\n", argv[0]); 617 print_bad_option(argv, optopt, optarg); 618 return (FAILURE); 619 } 620 621 /* No args other than nexus. Default to probing that nexus */ 622 if (!(parsed_args->flags & 623 (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS))) { 624 usage(argv[0]); 625 parsed_args->flags = 0; 626 return (SUCCESS); 627 } 628 629 /* 630 * Don't allow any options other than all-bus, verbose or 631 * quiet with probe command. Set default probe flags if nexus 632 * or leaf options are not specified. 633 */ 634 if (parsed_args->flags & (PROBETREE_FLAG | PROBEALL_FLAG)) { 635 if (parsed_args->flags & 636 ~(PROBE_FLAGS | QUIET_FLAG | VERBOSE_FLAG)) 637 error = B_TRUE; 638 } 639 640 /* 641 * Allow only read, write, quiet and verbose flags for 642 * interrupt command. Note that INO_SPEC_FLAG and CPU_SPEC_FLAG 643 * get set for interrupt command. 644 */ 645 if (parsed_args->flags & INTR_FLAG) { 646 if (parsed_args->flags & 647 ~(INTR_FLAG | VERBOSE_FLAG | QUIET_FLAG | 648 READ_FLAG | WRITE_FLAG | SHOWCTLR_FLAG | 649 SETGRP_FLAG | INO_ALL_FLAG | INO_SPEC_FLAG | 650 MSI_ALL_FLAG | MSI_SPEC_FLAG | CPU_SPEC_FLAG)) { 651 (void) fprintf(stderr, "%s: -v, -q, -r, -w, -c " 652 "-g are only options allowed with " 653 "interrupt command.\n", argv[0]); 654 error = B_TRUE; 655 } 656 657 /* Need cpu and ino values for interrupt set command. */ 658 if ((parsed_args->flags & WRITE_FLAG) && 659 !(parsed_args->flags & CPU_SPEC_FLAG) && 660 !((parsed_args->flags & INO_SPEC_FLAG) || 661 (parsed_args->flags & MSI_SPEC_FLAG))) { 662 (void) fprintf(stderr, 663 "%s: Both cpu and ino/msi must be " 664 "specified explicitly for interrupt " 665 "set command.\n", argv[0]); 666 error = B_TRUE; 667 } 668 669 /* Intr write and show ctlr flags are incompatible. */ 670 if ((parsed_args->flags & 671 (WRITE_FLAG + SHOWCTLR_FLAG)) == 672 (WRITE_FLAG + SHOWCTLR_FLAG)) { 673 (void) fprintf(stderr, 674 "%s: -w and -c are incompatible for " 675 "interrupt command.\n", argv[0]); 676 error = B_TRUE; 677 } 678 679 /* Intr setgrp flag valid only for intr writes. */ 680 if ((parsed_args->flags & (WRITE_FLAG + SETGRP_FLAG)) == 681 SETGRP_FLAG) { 682 (void) fprintf(stderr, 683 "%s: -g is incompatible with -r " 684 "for interrupt command.\n", argv[0]); 685 error = B_TRUE; 686 } 687 688 /* 689 * Disallow read & write together in interrupt command. 690 */ 691 if ((parsed_args->flags & (WRITE_FLAG | READ_FLAG)) == 692 (WRITE_FLAG | READ_FLAG)) { 693 (void) fprintf(stderr, "%s: Only one of -r and " 694 "-w can be specified in " 695 "interrupt command.\n", argv[0]); 696 error = B_TRUE; 697 } 698 } 699 700 /* Bytedump incompatible with some other options. */ 701 if ((parsed_args->flags & BYTEDUMP_FLAG) && 702 (parsed_args->flags & 703 (WRITE_FLAG | PROBE_FLAGS | INTR_FLAG))) { 704 (void) fprintf(stderr, 705 "%s: -b is incompatible with " 706 "another specified option.\n", argv[0]); 707 error = B_TRUE; 708 } 709 710 if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) { 711 712 if (!(parsed_args->flags & SIZE_FLAG)) { 713 parsed_args->size = DEFAULT_SIZE; 714 } 715 if ((parsed_args->flags & WRITE_FLAG) && 716 parsed_args->size < sizeof (uint64_t) && 717 (parsed_args->write_value >> 718 (parsed_args->size * BITS_PER_BYTE))) { 719 (void) fprintf(stderr, 720 "%s: Data to write is larger than " 721 "specified size.\n", argv[0]); 722 error = B_TRUE; 723 } 724 725 } else { /* Looping is compatible only with register cmds. */ 726 727 if (parsed_args->flags & LOOP_FLAG) { 728 (void) fprintf(stderr, "%s: -l is incompatible " 729 "with given command.\n", argv[0]); 730 error = B_TRUE; 731 } 732 } 733 734 /* Call out an erroneous -y and then ignore it. */ 735 if ((confirm) && (!(parsed_args->flags & BASE_SPEC_FLAG))) { 736 (void) fprintf(stderr, 737 "%s: -y is incompatible with given command." 738 " Ignoring.\n", argv[0]); 739 } 740 } 741 742 /* Now fill in the defaults and other holes. */ 743 if (!(error)) { 744 if (!(parsed_args->flags & (READ_FLAG | WRITE_FLAG))) { 745 parsed_args->flags |= READ_FLAG; 746 } 747 748 if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) { 749 if (!(parsed_args->flags & ENDIAN_FLAG)) { 750 parsed_args->big_endian = B_FALSE; 751 } 752 } 753 754 if (parsed_args->flags & BASE_SPEC_FLAG) { 755 if (!confirm) { 756 confirm = get_confirmation(); 757 } 758 if (!confirm) { 759 parsed_args->flags &= ~ALL_COMMANDS; 760 } 761 } 762 763 /* 764 * As far as other defaults are concerned: 765 * Other fields: bus, device, function, offset, default to 766 * zero. 767 */ 768 769 } else { /* An error occurred. */ 770 771 print_bad_option(argv, optopt, optarg); 772 } 773 return (error); 774 } 775 776 777 /* Module-private functions. */ 778 779 static void 780 print_bad_option(char *argv[], int optopt, char *optarg) 781 { 782 /* Illegal option operand */ 783 if (optarg != NULL) { 784 (void) fprintf(stderr, 785 "%s: illegal operand %s specified for option %c\n", 786 argv[0], optarg, optopt); 787 788 /* Illegal option */ 789 } else if (optopt != 0) { 790 (void) fprintf(stderr, 791 "%s: option %c is illegal or is missing an operand\n", 792 argv[0], optopt); 793 794 /* getopt wasn't even called. Bad device spec. */ 795 } else { 796 (void) fprintf(stderr, 797 "%s: device spec must start with %s or %s...\n", argv[0], 798 DEVNAME_START_PCI, DEVNAME_START_NIU); 799 } 800 801 (void) fprintf(stderr, 802 "%s: Type \"%s -h\" to get help on running this program.\n", 803 argv[0], argv[0]); 804 } 805 806 /* 807 * Warn the user and ask for confirmation. 808 */ 809 static boolean_t 810 get_confirmation() 811 { 812 int i, b; 813 814 (void) printf("WARNING: This cmd with a bad addr can panic " 815 "the system. Continue [y/n] (n)? "); 816 for (i = 0; ; i++) { 817 b = getchar(); 818 switch (b) { 819 case ' ': 820 case '\t': 821 break; 822 case 'y': 823 case 'Y': 824 return (B_TRUE); 825 break; 826 default: 827 return (B_FALSE); 828 break; 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 typedef enum { 902 bank = 0, 903 base 904 } nexus_opts_index_t; 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 typedef enum { 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 } bdf_opts_index_t; 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, uint8_t *ino_arg) 1290 { 1291 uint64_t value; 1292 int rval = SUCCESS; 1293 1294 if (strcmp(input, "all") == 0) { 1295 *flags_arg |= INO_ALL_FLAG; 1296 } else if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS) { 1297 *ino_arg = (uint8_t)value; 1298 1299 if (*ino_arg != value) { 1300 (void) fprintf(stderr, 1301 "ino argument must fit into 8 bits.\n"); 1302 rval = FAILURE; 1303 } else { 1304 *flags_arg |= INO_SPEC_FLAG; 1305 } 1306 } else { 1307 (void) fprintf(stderr, 1308 "Unrecognized option for -i\n"); 1309 rval = FAILURE; 1310 } 1311 1312 return (rval); 1313 } 1314 1315 1316 /* 1317 * Parse MSI options. This includes: 1318 * msi# | all 1319 * 1320 * input is the string of options to parse. flags_arg returns modified with 1321 * specified options set. Other args return their respective values. 1322 */ 1323 static int 1324 parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg) 1325 { 1326 uint64_t value; 1327 int rval = SUCCESS; 1328 1329 if (strcmp(input, "all") == 0) { 1330 *flags_arg |= MSI_ALL_FLAG; 1331 } else if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS) { 1332 *msi_arg = (uint16_t)value; 1333 1334 if (*msi_arg != value) { 1335 (void) fprintf(stderr, 1336 "msi argument must fit into 16 bits.\n"); 1337 rval = FAILURE; 1338 } else { 1339 *flags_arg |= MSI_SPEC_FLAG; 1340 } 1341 } else { 1342 (void) fprintf(stderr, 1343 "Unrecognized option for -m\n"); 1344 rval = FAILURE; 1345 } 1346 1347 return (rval); 1348 } 1349 1350 1351 /* 1352 * Parse interrupt set options. This includes: 1353 * cpu=number 1354 * 1355 * input is the string of options to parse. flags_arg returns modified with 1356 * specified options set. Other args return their respective values. 1357 */ 1358 static int 1359 parse_intr_set_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg) 1360 { 1361 uint64_t value; 1362 int rval = SUCCESS; 1363 1364 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS) { 1365 1366 if ((long)value > sysconf(_SC_CPUID_MAX)) { 1367 (void) fprintf(stderr, "Cpu argument " 1368 "exceeds maximum for this system type.\n"); 1369 rval = FAILURE; 1370 } else { 1371 *cpu_arg = (uint32_t)value; 1372 *flags_arg |= CPU_SPEC_FLAG; 1373 } 1374 } else { 1375 (void) fprintf(stderr, 1376 "Unrecognized option for -i -m -w\n"); 1377 rval = FAILURE; 1378 } 1379 1380 return (rval); 1381 } 1382 1383 1384 static int 1385 parse_probeone_opts( 1386 char *input, uint64_t *flags_arg, uint8_t *bus_arg, uint8_t *device_arg, 1387 uint8_t *func_arg) 1388 { 1389 typedef enum { 1390 bus = 0, 1391 dev = 1, 1392 func = 2, 1393 bdf = 3 1394 } p1_bdf_opts_index_t; 1395 1396 /* Needed by getsubopt(3C) */ 1397 static char *p1_bdf_opts[] = { 1398 "bus", 1399 "dev", 1400 "func", 1401 "bdf", 1402 NULL }; 1403 1404 char *value; /* Current suboption being processed. */ 1405 1406 int rval = SUCCESS; 1407 1408 while ((*input != '\0') && (rval == SUCCESS)) { 1409 switch (getsubopt(&input, p1_bdf_opts, &value)) { 1410 1411 /* bus=number */ 1412 case bdf: { 1413 char *bvalue, *dvalue, *fvalue; 1414 1415 if ((rval = extract_bdf(value, &bvalue, &dvalue, 1416 &fvalue)) != SUCCESS) { 1417 break; 1418 } 1419 if (bvalue) 1420 if ((rval = extract_bdf_arg(bvalue, "bus", 1421 BUS_SPEC_FLAG, flags_arg, bus_arg)) != 1422 SUCCESS) { 1423 break; 1424 } 1425 if (dvalue) 1426 if ((rval = extract_bdf_arg(dvalue, "dev", 1427 DEV_SPEC_FLAG, flags_arg, device_arg)) != 1428 SUCCESS) { 1429 break; 1430 } 1431 if (fvalue) 1432 rval = extract_bdf_arg(fvalue, "func", 1433 FUNC_SPEC_FLAG, flags_arg, func_arg); 1434 break; 1435 } 1436 1437 case bus: 1438 rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG, 1439 flags_arg, bus_arg); 1440 break; 1441 1442 /* dev=number */ 1443 case dev: 1444 rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG, 1445 flags_arg, device_arg); 1446 break; 1447 1448 /* func=number */ 1449 case func: 1450 rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG, 1451 flags_arg, func_arg); 1452 break; 1453 1454 default: 1455 (void) fprintf(stderr, "Unrecognized option for -p\n"); 1456 rval = FAILURE; 1457 break; 1458 } 1459 } 1460 1461 return (rval); 1462 } 1463 1464 1465 #ifdef DEBUG 1466 1467 static void 1468 dump_struct(pcitool_uiargs_t *dumpthis) { 1469 (void) printf("flags:0x%x\n", dumpthis->flags); 1470 (void) printf("bus:%d (0x%x)\n", 1471 dumpthis->bus, dumpthis->bus); 1472 (void) printf("device:%d (0x%x)\n", dumpthis->device, 1473 dumpthis->device); 1474 (void) printf("function:%d (0x%x)\n", dumpthis->function, 1475 dumpthis->function); 1476 (void) printf("write_value:%" PRIu64 " (0x%" PRIx64 ")\n", 1477 dumpthis->write_value, dumpthis->write_value); 1478 (void) printf("bank:%d (0x%x)\n", 1479 dumpthis->bank, dumpthis->bank); 1480 (void) printf("offset:%d (0x%x)\n", dumpthis->offset, dumpthis->offset); 1481 (void) printf("size:%d, endian:%s\n", dumpthis->size, 1482 dumpthis->big_endian ? "BIG" : "little"); 1483 (void) printf("ino:%d, cpu:%d\n", 1484 dumpthis->intr_ino, dumpthis->intr_cpu); 1485 } 1486 1487 #ifdef STANDALONE 1488 1489 /* Test program for this module. Useful when implementing new options. */ 1490 int 1491 main(int argc, char *argv[]) 1492 { 1493 int status; 1494 pcitool_uiargs_t parsed_args; 1495 1496 status = get_commandline_args(argc, argv, &parsed_args); 1497 if (status) { 1498 (void) printf("Error getting command.\n"); 1499 } 1500 dump_struct(&parsed_args); 1501 1502 return (SUCCESS); 1503 } 1504 1505 #endif /* STANDALONE */ 1506 #endif /* DEBUG */ 1507