8766 pcitool: typedef locally defined but not used
[unleashed.git] / usr / src / cmd / pcitool / pcitool_ui.c
blobddeccea4bf52500a0a538e4bf0dee43a3319d7a8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
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.
31 * Please see pcitool_usage.c for a complete commandline description.
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>
44 #include <sys/pci_tools.h>
46 #include "pcitool_ui.h"
49 * Uncomment the following for useful debugging / development options for this
50 * module only.
53 /* #define DEBUG 1 */
54 /* #define STANDALONE 1 */
56 #define DEVNAME_START_PCI "/pci"
57 #define DEVNAME_START_NIU "/niu"
59 /* Default read/write size when -s not specified. */
60 #define DEFAULT_SIZE 4
62 /* For get_value64 */
63 #define HEX_ONLY B_TRUE
64 #define BASE_BY_PREFIX B_FALSE
66 #define BITS_PER_BYTE 8
69 * This defines which main options can be specified by the user.
70 * Options with colons after them require arguments.
72 static char *opt_string = ":n:d:i:m:p:rw:o:s:e:b:vaqlcxgy";
74 /* This defines options used singly and only by themselves (no nexus). */
75 static char *no_dev_opt_string = "ahpqv";
77 static void print_bad_option(char *argv[], int optopt, char *optarg);
78 static boolean_t get_confirmation(void);
79 static int get_value64(char *value_str, uint64_t *value, boolean_t hex_only);
80 static int parse_nexus_opts(char *input, uint64_t *flags_arg, uint8_t *bank_arg,
81 uint64_t *base_addr_arg);
82 static int extract_bdf_arg(char *cvalue, char *fld, uint64_t fld_flag,
83 uint64_t *all_flags, uint8_t *ivalue);
84 static int extract_bdf(char *value, char **bvalue_p, char **dvalue_p,
85 char **fvalue_p);
86 static int parse_device_opts(char *input, uint64_t *flags_arg,
87 uint8_t *bus_arg, uint8_t *device_arg, uint8_t *func_arg,
88 uint8_t *bank_arg);
89 static int parse_ino_opts(char *input, uint64_t *flags_arg,
90 uint32_t *cpu_arg, uint8_t *ino_arg);
91 static int parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg);
92 static int parse_intr_set_opts(char *input, uint64_t *flags_arg,
93 uint32_t *cpu_arg);
94 static int parse_probeone_opts(char *input, uint64_t *flags_arg,
95 uint8_t *bus_arg, uint8_t *device_arg, uint8_t *func_arg);
97 #ifdef DEBUG
98 void dump_struct(pcitool_uiargs_t *dump_this);
99 #endif
101 /* Exported functions. */
104 * Main commandline argument parsing routine.
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.
111 get_commandline_args(int argc, char *argv[], pcitool_uiargs_t *parsed_args)
113 int c; /* Current option being processed. */
114 boolean_t error = B_FALSE;
115 boolean_t confirm = B_FALSE;
116 uint64_t recv64;
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. */
124 opterr = 0;
126 bzero(parsed_args, sizeof (pcitool_uiargs_t));
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);
135 /* 1st arg is not a device name. */
136 if ((strstr(argv[1], DEVNAME_START_PCI) != argv[1]) &&
137 (strstr(argv[1], DEVNAME_START_NIU) != argv[1])) {
139 /* Default is to probe all trees accounting for bus ranges. */
140 parsed_args->flags = PROBEALL_FLAG | PROBERNG_FLAG;
142 /* Loop thru the options until complete or an error is found. */
143 while (((c = getopt(argc, argv, no_dev_opt_string)) != -1) &&
144 (error == B_FALSE)) {
146 switch (c) {
148 /* Help requested. */
149 case 'h':
150 usage(argv[0]);
151 parsed_args->flags = 0;
152 return (SUCCESS);
154 case 'p':
155 /* Take default probe mode */
156 break;
158 case 'a':
160 * Enable display of ALL bus numbers.
162 * This takes precidence over PROBERNG as -a
163 * is explicitly specified.
165 parsed_args->flags &= ~PROBERNG_FLAG;
166 break;
168 case 'q':
169 parsed_args->flags |= QUIET_FLAG;
170 break;
172 /* Verbose mode for full probe. */
173 case 'v':
174 parsed_args->flags |= VERBOSE_FLAG;
175 break;
177 default:
178 error = B_TRUE;
179 break;
183 /* Check for values straggling at the end of the command. */
184 if (optind != argc) {
185 (void) fprintf(stderr, "%s: Unrecognized parameter "
186 "at the end of the command.\n", argv[0]);
187 error = B_TRUE;
190 if (error) {
191 print_bad_option(argv, optopt, optarg);
192 return (FAILURE);
195 return (SUCCESS);
198 /* Device node specified on commandline. */
200 /* Skip argv[1] before continuing below. */
201 optind++;
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)) {
207 switch (c) {
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;
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;
227 break;
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;
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;
248 break;
250 /* Interrupt */
251 case 'i':
252 if (parsed_args->flags & (LEAF_FLAG |
253 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
254 (void) fprintf(stderr, "%s: -i set with -m, "
255 "-n, -d or -p or is set twice\n", argv[0]);
256 error = B_TRUE;
257 break;
259 parsed_args->flags |= INTR_FLAG;
261 /* parse input to get ino value. */
262 if (parse_ino_opts(optarg, &parsed_args->flags,
263 &parsed_args->old_cpu,
264 &parsed_args->intr_ino) != SUCCESS) {
265 (void) fprintf(stderr,
266 "%s: Error parsing interrupt options\n",
267 argv[0]);
268 error = B_TRUE;
270 break;
271 /* Interrupt */
272 case 'm':
273 if (parsed_args->flags & (LEAF_FLAG |
274 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
275 (void) fprintf(stderr, "%s: -m set with -i, "
276 "-n, -d or -p or is set twice\n", argv[0]);
277 error = B_TRUE;
278 break;
280 parsed_args->flags |= INTR_FLAG;
282 /* parse input to get msi value. */
283 if (parse_msi_opts(optarg, &parsed_args->flags,
284 &parsed_args->intr_msi) != SUCCESS) {
285 (void) fprintf(stderr,
286 "%s: Error parsing interrupt options\n",
287 argv[0]);
288 error = B_TRUE;
290 break;
291 /* Probe */
292 case 'p':
293 if (parsed_args->flags & (LEAF_FLAG |
294 NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS)) {
295 (void) fprintf(stderr, "%s: -p set with "
296 "-n, -d or -i or is set twice\n", argv[0]);
297 error = B_TRUE;
298 break;
301 /* Process -p with no dedicated options to it. */
302 if (optarg[0] == '-') {
303 optind--;
305 /* Probe given tree observing ranges */
306 parsed_args->flags |=
307 (PROBETREE_FLAG | PROBERNG_FLAG);
308 continue;
311 /* parse input to get ino value. */
312 if (parse_probeone_opts(optarg, &parsed_args->flags,
313 &parsed_args->bus, &parsed_args->device,
314 &parsed_args->function) != SUCCESS) {
315 (void) fprintf(stderr,
316 "%s: Error parsing probe options\n",
317 argv[0]);
318 error = B_TRUE;
319 } else {
321 * parse_probeone_opts found options to
322 * set up bdf.
324 parsed_args->flags |= PROBEDEV_FLAG;
326 break;
328 /* Probe all busses */
329 case 'a':
330 /* Must follow -p, and -p must have no bdf. */
331 if (!(parsed_args->flags & PROBETREE_FLAG)) {
332 error = B_TRUE;
333 break;
336 parsed_args->flags &= ~PROBERNG_FLAG;
337 break;
339 /* Read */
340 case 'r':
341 if (!(parsed_args->flags &
342 (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) {
343 error = B_TRUE;
344 break;
348 * Allow read and write to be set together for now,
349 * since this means write then read back for device and
350 * nexus accesses. Check for this and disallow with
351 * interrupt command later.
353 parsed_args->flags |= READ_FLAG;
354 break;
356 /* Write */
357 case 'w':
358 if (!(parsed_args->flags &
359 (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) {
360 error = B_TRUE;
361 break;
363 if (parsed_args->flags & WRITE_FLAG) {
364 (void) fprintf(stderr, "%s: -w set twice\n",
365 argv[0]);
366 error = B_TRUE;
367 break;
371 * For device and nexus, get a single register value
372 * to write.
374 if (parsed_args->flags & (NEXUS_FLAG | LEAF_FLAG)) {
375 parsed_args->flags |= WRITE_FLAG;
376 if (get_value64(optarg,
377 &parsed_args->write_value, HEX_ONLY) !=
378 SUCCESS) {
379 (void) fprintf(stderr,
380 "%s: Error reading value to "
381 "write.\n", argv[0]);
382 error = B_TRUE;
383 break;
386 /* For interrupt, parse input to get cpu value. */
387 } else if (parsed_args->flags & INTR_FLAG) {
388 parsed_args->flags |= WRITE_FLAG;
389 if (parse_intr_set_opts(optarg,
390 &parsed_args->flags,
391 &parsed_args->intr_cpu) != SUCCESS) {
392 (void) fprintf(stderr, "%s: Error "
393 "parsing interrupt options.\n",
394 argv[0]);
395 error = B_TRUE;
396 break;
399 } else {
400 error = B_TRUE;
401 break;
403 break;
405 /* Offset */
406 case 'o':
407 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
408 error = B_TRUE;
409 break;
411 if (parsed_args->flags & OFFSET_FLAG) {
412 (void) fprintf(stderr, "%s: -o set twice\n",
413 argv[0]);
414 error = B_TRUE;
415 break;
417 parsed_args->flags |= OFFSET_FLAG;
418 if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) {
419 (void) fprintf(stderr,
420 "%s: Error in offset argument\n", argv[0]);
421 error = B_TRUE;
422 break;
424 parsed_args->offset = (uint32_t)recv64;
425 if (parsed_args->offset != recv64) {
426 (void) fprintf(stderr, "%s: Offset argument "
427 "too large for 32 bits\n", argv[0]);
428 error = B_TRUE;
429 break;
431 break;
433 /* Size */
434 case 's':
435 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
436 error = B_TRUE;
437 break;
439 if (parsed_args->flags & SIZE_FLAG) {
440 (void) fprintf(stderr, "%s: -s set twice\n",
441 argv[0]);
442 error = B_TRUE;
443 break;
445 parsed_args->flags |= SIZE_FLAG;
446 if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) {
447 (void) fprintf(stderr,
448 "%s: Error in size argument\n", argv[0]);
449 error = B_TRUE;
450 break;
452 switch (recv64) {
453 case 1:
454 case 2:
455 case 4:
456 case 8:
457 break;
458 default:
459 error = B_TRUE;
460 (void) fprintf(stderr,
461 "%s: Error in size argument\n", argv[0]);
462 break;
464 parsed_args->size |= (uint8_t)recv64;
465 break;
467 /* Endian. */
468 case 'e':
469 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
470 error = B_TRUE;
471 break;
473 if (parsed_args->flags & ENDIAN_FLAG) {
474 (void) fprintf(stderr, "%s: -e set twice\n",
475 argv[0]);
476 error = B_TRUE;
477 break;
479 parsed_args->flags |= ENDIAN_FLAG;
481 /* Only a single character allowed. */
482 if (optarg[1] != '\0') {
483 (void) fprintf(stderr,
484 "%s: Error in endian argument\n", argv[0]);
485 error = B_TRUE;
486 break;
489 switch (optarg[0]) {
490 case 'b':
491 parsed_args->big_endian = B_TRUE;
492 break;
493 case 'l':
494 break;
495 default:
496 (void) fprintf(stderr,
497 "%s: Error in endian argument\n", argv[0]);
498 error = B_TRUE;
499 break;
501 break;
503 /* (Byte)dump */
504 case 'b':
505 if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
506 error = B_TRUE;
507 break;
509 if (parsed_args->flags & BYTEDUMP_FLAG) {
510 (void) fprintf(stderr, "%s: -b set twice\n",
511 argv[0]);
512 error = B_TRUE;
513 break;
515 parsed_args->flags |= BYTEDUMP_FLAG;
516 if (get_value64(optarg, &recv64, HEX_ONLY) != SUCCESS) {
517 (void) fprintf(stderr, "%s: Error in "
518 "bytedump argument\n", argv[0]);
519 error = B_TRUE;
520 break;
522 parsed_args->bytedump_amt = (uint32_t)recv64;
523 if (parsed_args->bytedump_amt != recv64) {
524 (void) fprintf(stderr, "%s: Bytedump amount "
525 "too large for 32 bits\n", argv[0]);
526 error = B_TRUE;
527 break;
529 break;
531 /* Verbose. */
532 case 'v':
533 parsed_args->flags |= VERBOSE_FLAG;
534 break;
537 * Quiet - no errors reported as messages.
538 * (Status still returned by program, however.)
540 case 'q':
541 parsed_args->flags |= QUIET_FLAG;
542 break;
544 /* Loop. */
545 case 'l':
546 parsed_args->flags |= LOOP_FLAG;
547 break;
550 * Dump characters with bytedump (-b).
551 * Show controller info with -i.
553 case 'c':
554 if (parsed_args->flags & BYTEDUMP_FLAG) {
555 parsed_args->flags |= CHARDUMP_FLAG;
557 } else if (parsed_args->flags & INTR_FLAG) {
558 parsed_args->flags |= SHOWCTLR_FLAG;
560 } else {
561 error = B_TRUE;
563 break;
565 /* Continue on errors with bytedump (-b). */
566 case 'x':
567 if (!(parsed_args->flags & BYTEDUMP_FLAG)) {
568 error = B_TRUE;
569 break;
571 parsed_args->flags |= ERRCONT_FLAG;
572 break;
574 case 'g':
575 if (!(parsed_args->flags & INTR_FLAG)) {
576 error = B_TRUE;
577 break;
579 parsed_args->flags |= SETGRP_FLAG;
580 break;
582 /* Take -y as confirmation and don't ask (where applicable). */
583 case 'y':
584 confirm = B_TRUE;
585 break;
587 /* Option without operand. */
588 case ':':
589 switch (optopt) {
590 case 'p':
591 /* Allow -p without bdf spec. */
592 parsed_args->flags |=
593 (PROBETREE_FLAG | PROBERNG_FLAG);
594 break;
595 default:
596 error = B_TRUE;
597 break;
599 break;
601 /* Unrecognized option. */
602 case '?':
603 error = B_TRUE;
604 break;
609 * Commandline has been parsed. Check for errors which can be checked
610 * only after commandline parsing is complete.
613 if (!error) {
615 /* Check for values straggling at the end of the command. */
616 if (optind != argc) {
617 (void) fprintf(stderr, "%s: Unrecognized parameter "
618 "at the end of the command.\n", argv[0]);
619 print_bad_option(argv, optopt, optarg);
620 return (FAILURE);
623 /* No args other than nexus. Default to probing that nexus */
624 if (!(parsed_args->flags &
625 (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG | PROBE_FLAGS))) {
626 usage(argv[0]);
627 parsed_args->flags = 0;
628 return (SUCCESS);
632 * Don't allow any options other than all-bus, verbose or
633 * quiet with probe command. Set default probe flags if nexus
634 * or leaf options are not specified.
636 if (parsed_args->flags & (PROBETREE_FLAG | PROBEALL_FLAG)) {
637 if (parsed_args->flags &
638 ~(PROBE_FLAGS | QUIET_FLAG | VERBOSE_FLAG))
639 error = B_TRUE;
643 * Allow only read, write, quiet and verbose flags for
644 * interrupt command. Note that INO_SPEC_FLAG and CPU_SPEC_FLAG
645 * get set for interrupt command.
647 if (parsed_args->flags & INTR_FLAG) {
648 if (parsed_args->flags &
649 ~(INTR_FLAG | VERBOSE_FLAG | QUIET_FLAG |
650 READ_FLAG | WRITE_FLAG | SHOWCTLR_FLAG |
651 SETGRP_FLAG | INO_ALL_FLAG | INO_SPEC_FLAG |
652 MSI_ALL_FLAG | MSI_SPEC_FLAG | CPU_SPEC_FLAG)) {
653 (void) fprintf(stderr, "%s: -v, -q, -r, -w, -c "
654 "-g are only options allowed with "
655 "interrupt command.\n", argv[0]);
656 error = B_TRUE;
659 /* Need cpu and ino values for interrupt set command. */
660 if ((parsed_args->flags & WRITE_FLAG) &&
661 !(parsed_args->flags & CPU_SPEC_FLAG) &&
662 !((parsed_args->flags & INO_SPEC_FLAG) ||
663 (parsed_args->flags & MSI_SPEC_FLAG))) {
664 (void) fprintf(stderr,
665 "%s: Both cpu and ino/msi must be "
666 "specified explicitly for interrupt "
667 "set command.\n", argv[0]);
668 error = B_TRUE;
671 /* Intr write and show ctlr flags are incompatible. */
672 if ((parsed_args->flags &
673 (WRITE_FLAG + SHOWCTLR_FLAG)) ==
674 (WRITE_FLAG + SHOWCTLR_FLAG)) {
675 (void) fprintf(stderr,
676 "%s: -w and -c are incompatible for "
677 "interrupt command.\n", argv[0]);
678 error = B_TRUE;
681 /* Intr setgrp flag valid only for intr writes. */
682 if ((parsed_args->flags & (WRITE_FLAG + SETGRP_FLAG)) ==
683 SETGRP_FLAG) {
684 (void) fprintf(stderr,
685 "%s: -g is incompatible with -r "
686 "for interrupt command.\n", argv[0]);
687 error = B_TRUE;
691 * Disallow read & write together in interrupt command.
693 if ((parsed_args->flags & (WRITE_FLAG | READ_FLAG)) ==
694 (WRITE_FLAG | READ_FLAG)) {
695 (void) fprintf(stderr, "%s: Only one of -r and "
696 "-w can be specified in "
697 "interrupt command.\n", argv[0]);
698 error = B_TRUE;
702 /* Bytedump incompatible with some other options. */
703 if ((parsed_args->flags & BYTEDUMP_FLAG) &&
704 (parsed_args->flags &
705 (WRITE_FLAG | PROBE_FLAGS | INTR_FLAG))) {
706 (void) fprintf(stderr,
707 "%s: -b is incompatible with "
708 "another specified option.\n", argv[0]);
709 error = B_TRUE;
712 if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) {
714 if (!(parsed_args->flags & SIZE_FLAG)) {
715 parsed_args->size = DEFAULT_SIZE;
717 if ((parsed_args->flags & WRITE_FLAG) &&
718 parsed_args->size < sizeof (uint64_t) &&
719 (parsed_args->write_value >>
720 (parsed_args->size * BITS_PER_BYTE))) {
721 (void) fprintf(stderr,
722 "%s: Data to write is larger than "
723 "specified size.\n", argv[0]);
724 error = B_TRUE;
727 } else { /* Looping is compatible only with register cmds. */
729 if (parsed_args->flags & LOOP_FLAG) {
730 (void) fprintf(stderr, "%s: -l is incompatible "
731 "with given command.\n", argv[0]);
732 error = B_TRUE;
736 /* Call out an erroneous -y and then ignore it. */
737 if ((confirm) && (!(parsed_args->flags & BASE_SPEC_FLAG))) {
738 (void) fprintf(stderr,
739 "%s: -y is incompatible with given command."
740 " Ignoring.\n", argv[0]);
744 /* Now fill in the defaults and other holes. */
745 if (!(error)) {
746 if (!(parsed_args->flags & (READ_FLAG | WRITE_FLAG))) {
747 parsed_args->flags |= READ_FLAG;
750 if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) {
751 if (!(parsed_args->flags & ENDIAN_FLAG)) {
752 parsed_args->big_endian = B_FALSE;
756 if (parsed_args->flags & BASE_SPEC_FLAG) {
757 if (!confirm) {
758 confirm = get_confirmation();
760 if (!confirm) {
761 parsed_args->flags &= ~ALL_COMMANDS;
766 * As far as other defaults are concerned:
767 * Other fields: bus, device, function, offset, default to
768 * zero.
771 } else { /* An error occurred. */
773 print_bad_option(argv, optopt, optarg);
775 return (error);
779 /* Module-private functions. */
781 static void
782 print_bad_option(char *argv[], int optopt, char *optarg)
784 /* Illegal option operand */
785 if (optarg != NULL) {
786 (void) fprintf(stderr,
787 "%s: illegal operand %s specified for option %c\n",
788 argv[0], optarg, optopt);
790 /* Illegal option */
791 } else if (optopt != 0) {
792 (void) fprintf(stderr,
793 "%s: option %c is illegal or is missing an operand\n",
794 argv[0], optopt);
796 /* getopt wasn't even called. Bad device spec. */
797 } else {
798 (void) fprintf(stderr,
799 "%s: device spec must start with %s or %s...\n", argv[0],
800 DEVNAME_START_PCI, DEVNAME_START_NIU);
803 (void) fprintf(stderr,
804 "%s: Type \"%s -h\" to get help on running this program.\n",
805 argv[0], argv[0]);
809 * Warn the user and ask for confirmation.
811 static boolean_t
812 get_confirmation()
814 int i, b;
816 (void) printf("WARNING: This cmd with a bad addr can panic "
817 "the system. Continue [y/n] (n)? ");
818 for (i = 0; ; i++) {
819 b = getchar();
820 switch (b) {
821 case ' ':
822 case '\t':
823 break;
824 case 'y':
825 case 'Y':
826 return (B_TRUE);
827 default:
828 return (B_FALSE);
835 * Given a digit string, return a 64 bit value.
837 * If the hex_only arg is true, interpret all strings as hex.
838 * Otherwise, interpret as strtoull(3C) does with base=0.
840 static int
841 get_value64(char *value_str, uint64_t *value, boolean_t hex_only)
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";
849 char *digit_string;
850 char *string_to_check;
852 if ((value_str == NULL) || (strlen(value_str) == 0)) {
853 (void) fprintf(stderr, "Missing value argument.\n");
854 return (FAILURE);
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;
872 * Verify value is all proper digits.
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.
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);
883 *value = strtoull(value_str, NULL, (hex_only ? 16 : 0));
885 return (SUCCESS);
890 * Parse nexus options. This includes:
891 * bank=number
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.
897 static int
898 parse_nexus_opts(char *input, uint64_t *flags_arg, uint8_t *bank_arg,
899 uint64_t *base_addr_arg)
901 enum nexus_opts_index {
902 bank = 0,
903 base
906 static char *nexus_opts[] = {
907 "bank",
908 "base",
909 NULL
912 char *value;
913 uint64_t recv64;
915 int rval = SUCCESS;
917 if (input == NULL) {
918 (void) fprintf(stderr, "Missing argument.\n");
919 return (FAILURE);
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;
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;
937 if (value == NULL) {
938 (void) fprintf(stderr, "Missing bank value.\n");
939 rval = FAILURE;
940 break;
942 if ((rval = get_value64(value, &recv64, HEX_ONLY)) !=
943 SUCCESS) {
944 break;
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;
953 *flags_arg |= BANK_SPEC_FLAG;
954 break;
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;
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;
969 if (value == NULL) {
970 (void) fprintf(stderr,
971 "Missing base addr value.\n");
972 rval = FAILURE;
973 break;
975 if ((rval = get_value64(value, base_addr_arg,
976 HEX_ONLY)) != SUCCESS) {
977 break;
979 *flags_arg |= BASE_SPEC_FLAG;
980 break;
982 default:
983 (void) fprintf(stderr, "Unrecognized option for -n\n");
984 rval = FAILURE;
985 break;
989 return (rval);
993 static int
994 extract_bdf_arg(char *cvalue, char *fld, uint64_t fld_flag, uint64_t *all_flags,
995 uint8_t *ivalue)
997 uint64_t recv64;
999 if (*all_flags & fld_flag) {
1000 (void) fprintf(stderr,
1001 "The %s is specified more than once.\n", fld);
1002 return (FAILURE);
1004 if (get_value64(cvalue, &recv64, HEX_ONLY) != SUCCESS)
1005 return (FAILURE);
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);
1016 *all_flags |= fld_flag;
1017 return (SUCCESS);
1021 static int extract_bdf(char *value, char **bvalue_p, char **dvalue_p,
1022 char **fvalue_p)
1024 char *strtok_state;
1025 char *dummy;
1026 static char *separator = ".";
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);
1033 /* Return failure only if too many values specified. */
1034 return ((dummy) ? FAILURE : SUCCESS);
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
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.
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)
1061 /* Needed by getsubopt(3C) */
1062 enum bdf_opts_index {
1063 bus = 0,
1064 dev = 1,
1065 func = 2,
1066 bdf = 3,
1067 bank = 4,
1068 config = 5,
1069 bar0 = 6,
1070 bar1 = 7,
1071 bar2 = 8,
1072 bar3 = 9,
1073 bar4 = 10,
1074 bar5 = 11,
1075 rom = 12
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 };
1095 char *value; /* Current suboption being processed. */
1096 uint64_t recv64; /* Temporary value. */
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"};
1102 int rval = SUCCESS;
1104 while ((*input != '\0') && (rval == SUCCESS)) {
1105 switch (getsubopt(&input, bdf_opts, &value)) {
1107 /* bus=number */
1108 case bdf: {
1109 char *bvalue, *dvalue, *fvalue;
1111 if ((rval = extract_bdf(value, &bvalue, &dvalue,
1112 &fvalue)) != SUCCESS) {
1113 break;
1116 if (!bvalue | !dvalue | !fvalue) {
1117 break;
1120 if ((rval = extract_bdf_arg(bvalue, "bus",
1121 BUS_SPEC_FLAG, flags_arg, bus_arg)) != SUCCESS) {
1122 break;
1124 if ((rval = extract_bdf_arg(dvalue, "dev",
1125 DEV_SPEC_FLAG, flags_arg, device_arg)) != SUCCESS) {
1126 break;
1128 rval = extract_bdf_arg(fvalue, "func",
1129 FUNC_SPEC_FLAG, flags_arg, func_arg);
1130 break;
1133 case bus:
1134 rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG,
1135 flags_arg, bus_arg);
1136 break;
1138 /* dev=number */
1139 case dev:
1140 rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG,
1141 flags_arg, device_arg);
1142 break;
1144 /* func=number */
1145 case func:
1146 rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG,
1147 flags_arg, func_arg);
1148 break;
1150 /* bank=number */
1151 case bank:
1152 if (*flags_arg & BANK_SPEC_FLAG) {
1153 (void) fprintf(stderr, bank_err);
1154 rval = FAILURE;
1155 break;
1157 if ((rval = get_value64(value, &recv64, HEX_ONLY)) !=
1158 SUCCESS) {
1159 break;
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;
1168 *flags_arg |= BANK_SPEC_FLAG;
1169 break;
1171 /* config */
1172 case config:
1173 if (*flags_arg & BANK_SPEC_FLAG) {
1174 (void) fprintf(stderr, bank_err);
1175 rval = FAILURE;
1176 break;
1178 *bank_arg = PCITOOL_CONFIG;
1179 *flags_arg |= BANK_SPEC_FLAG;
1180 break;
1182 /* bar0 */
1183 case bar0:
1184 if (*flags_arg & BANK_SPEC_FLAG) {
1185 (void) fprintf(stderr, bank_err);
1186 rval = FAILURE;
1187 break;
1189 *bank_arg = PCITOOL_BAR0;
1190 *flags_arg |= BANK_SPEC_FLAG;
1191 break;
1193 /* bar1 */
1194 case bar1:
1195 if (*flags_arg & BANK_SPEC_FLAG) {
1196 (void) fprintf(stderr, bank_err);
1197 rval = FAILURE;
1198 break;
1200 *bank_arg = PCITOOL_BAR1;
1201 *flags_arg |= BANK_SPEC_FLAG;
1202 break;
1204 /* bar2 */
1205 case bar2:
1206 if (*flags_arg & BANK_SPEC_FLAG) {
1207 (void) fprintf(stderr, bank_err);
1208 rval = FAILURE;
1209 break;
1211 *bank_arg = PCITOOL_BAR2;
1212 *flags_arg |= BANK_SPEC_FLAG;
1213 break;
1215 /* bar3 */
1216 case bar3:
1217 if (*flags_arg & BANK_SPEC_FLAG) {
1218 (void) fprintf(stderr, bank_err);
1219 rval = FAILURE;
1220 break;
1222 *bank_arg = PCITOOL_BAR3;
1223 *flags_arg |= BANK_SPEC_FLAG;
1224 break;
1226 /* bar4 */
1227 case bar4:
1228 if (*flags_arg & BANK_SPEC_FLAG) {
1229 (void) fprintf(stderr, bank_err);
1230 rval = FAILURE;
1231 break;
1233 *bank_arg = PCITOOL_BAR4;
1234 *flags_arg |= BANK_SPEC_FLAG;
1235 break;
1237 /* bar5 */
1238 case bar5:
1239 if (*flags_arg & BANK_SPEC_FLAG) {
1240 (void) fprintf(stderr, bank_err);
1241 rval = FAILURE;
1242 break;
1244 *bank_arg = PCITOOL_BAR5;
1245 *flags_arg |= BANK_SPEC_FLAG;
1246 break;
1248 /* rom */
1249 case rom:
1250 if (*flags_arg & BANK_SPEC_FLAG) {
1251 (void) fprintf(stderr, bank_err);
1252 rval = FAILURE;
1253 break;
1255 *bank_arg = PCITOOL_ROM;
1256 *flags_arg |= BANK_SPEC_FLAG;
1257 break;
1259 default:
1260 (void) fprintf(stderr, "Unrecognized option for -d\n");
1261 rval = FAILURE;
1262 break;
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;
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;
1277 return (rval);
1282 * Parse INO options. This includes:
1283 * ino# | all
1285 * input is the string of options to parse. flags_arg returns modified with
1286 * specified options set. Other args return their respective values.
1288 static int
1289 parse_ino_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg,
1290 uint8_t *ino_arg)
1292 uint64_t value;
1293 char *charvalue;
1294 int rval = SUCCESS;
1296 if (strcmp(input, "all") == 0) {
1297 *flags_arg |= INO_ALL_FLAG;
1298 #ifdef __x86
1299 } else if (strstr(input, ",") == NULL) {
1300 (void) fprintf(stderr,
1301 "Interrupt format should be <cpu#,ino#>.\n");
1302 rval = FAILURE;
1303 #else
1304 } else if (strstr(input, ",") == NULL) {
1305 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1306 *ino_arg = (uint8_t)value;
1308 if (*ino_arg != value) {
1309 (void) fprintf(stderr,
1310 "ino argument must fit into 8 bits.\n");
1311 rval = FAILURE;
1312 } else {
1313 *flags_arg |= INO_SPEC_FLAG;
1315 #endif
1316 } else if (charvalue = strtok(input, ",")) {
1317 if ((rval =
1318 get_value64(charvalue, &value, HEX_ONLY)) == SUCCESS) {
1319 *cpu_arg = (int)value;
1322 input = strtok(NULL, ",");
1323 if (input == NULL) {
1324 (void) fprintf(stderr, "ino argument is need.\n");
1325 return (FAILURE);
1328 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1329 *ino_arg = (uint8_t)value;
1331 if (*ino_arg != value) {
1332 (void) fprintf(stderr,
1333 "ino argument must fit into 8 bits.\n");
1334 rval = FAILURE;
1335 } else {
1336 *flags_arg |= INO_SPEC_FLAG;
1338 } else {
1339 (void) fprintf(stderr,
1340 "Unrecognized option for -i\n");
1341 rval = FAILURE;
1344 return (rval);
1349 * Parse MSI options. This includes:
1350 * msi# | all
1352 * input is the string of options to parse. flags_arg returns modified with
1353 * specified options set. Other args return their respective values.
1355 static int
1356 parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg)
1358 uint64_t value;
1359 int rval = SUCCESS;
1361 if (strcmp(input, "all") == 0) {
1362 *flags_arg |= MSI_ALL_FLAG;
1363 } else if (strstr(input, ",") == NULL) {
1364 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1365 *msi_arg = (uint16_t)value;
1367 if (*msi_arg != value) {
1368 (void) fprintf(stderr,
1369 "msi argument must fit into 16 bits.\n");
1370 rval = FAILURE;
1371 } else {
1372 *flags_arg |= MSI_SPEC_FLAG;
1374 } else if (strtok(input, ",")) {
1375 input = strtok(NULL, ",");
1376 if (input == NULL) {
1377 (void) fprintf(stderr, "msi argument is need.\n");
1378 return (FAILURE);
1381 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1382 *msi_arg = (uint16_t)value;
1384 if (*msi_arg != value) {
1385 (void) fprintf(stderr,
1386 "msi argument must fit into 16 bits.\n");
1387 rval = FAILURE;
1388 } else {
1389 *flags_arg |= MSI_SPEC_FLAG;
1391 } else {
1392 (void) fprintf(stderr,
1393 "Unrecognized option for -m\n");
1394 rval = FAILURE;
1397 return (rval);
1402 * Parse interrupt set options. This includes:
1403 * cpu=number
1405 * input is the string of options to parse. flags_arg returns modified with
1406 * specified options set. Other args return their respective values.
1408 static int
1409 parse_intr_set_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg)
1411 uint64_t value;
1412 int rval = SUCCESS;
1414 if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS) {
1416 if ((long)value > sysconf(_SC_CPUID_MAX)) {
1417 (void) fprintf(stderr, "Cpu argument "
1418 "exceeds maximum for this system type.\n");
1419 rval = FAILURE;
1420 } else {
1421 *cpu_arg = (uint32_t)value;
1422 *flags_arg |= CPU_SPEC_FLAG;
1424 } else {
1425 (void) fprintf(stderr,
1426 "Unrecognized option for -i -m -w\n");
1427 rval = FAILURE;
1430 return (rval);
1434 static int
1435 parse_probeone_opts(
1436 char *input, uint64_t *flags_arg, uint8_t *bus_arg, uint8_t *device_arg,
1437 uint8_t *func_arg)
1439 enum p1_bdf_opts_index {
1440 bus = 0,
1441 dev = 1,
1442 func = 2,
1443 bdf = 3
1446 /* Needed by getsubopt(3C) */
1447 static char *p1_bdf_opts[] = {
1448 "bus",
1449 "dev",
1450 "func",
1451 "bdf",
1452 NULL };
1454 char *value; /* Current suboption being processed. */
1456 int rval = SUCCESS;
1458 while ((*input != '\0') && (rval == SUCCESS)) {
1459 switch (getsubopt(&input, p1_bdf_opts, &value)) {
1461 /* bus=number */
1462 case bdf: {
1463 char *bvalue, *dvalue, *fvalue;
1465 if ((rval = extract_bdf(value, &bvalue, &dvalue,
1466 &fvalue)) != SUCCESS) {
1467 break;
1469 if (bvalue)
1470 if ((rval = extract_bdf_arg(bvalue, "bus",
1471 BUS_SPEC_FLAG, flags_arg, bus_arg)) !=
1472 SUCCESS) {
1473 break;
1475 if (dvalue)
1476 if ((rval = extract_bdf_arg(dvalue, "dev",
1477 DEV_SPEC_FLAG, flags_arg, device_arg)) !=
1478 SUCCESS) {
1479 break;
1481 if (fvalue)
1482 rval = extract_bdf_arg(fvalue, "func",
1483 FUNC_SPEC_FLAG, flags_arg, func_arg);
1484 break;
1487 case bus:
1488 rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG,
1489 flags_arg, bus_arg);
1490 break;
1492 /* dev=number */
1493 case dev:
1494 rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG,
1495 flags_arg, device_arg);
1496 break;
1498 /* func=number */
1499 case func:
1500 rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG,
1501 flags_arg, func_arg);
1502 break;
1504 default:
1505 (void) fprintf(stderr, "Unrecognized option for -p\n");
1506 rval = FAILURE;
1507 break;
1511 return (rval);
1515 #ifdef DEBUG
1517 static void
1518 dump_struct(pcitool_uiargs_t *dumpthis)
1520 (void) printf("flags:0x%x\n", dumpthis->flags);
1521 (void) printf("bus:%d (0x%x)\n",
1522 dumpthis->bus, dumpthis->bus);
1523 (void) printf("device:%d (0x%x)\n", dumpthis->device,
1524 dumpthis->device);
1525 (void) printf("function:%d (0x%x)\n", dumpthis->function,
1526 dumpthis->function);
1527 (void) printf("write_value:%" PRIu64 " (0x%" PRIx64 ")\n",
1528 dumpthis->write_value, dumpthis->write_value);
1529 (void) printf("bank:%d (0x%x)\n",
1530 dumpthis->bank, dumpthis->bank);
1531 (void) printf("offset:%d (0x%x)\n", dumpthis->offset, dumpthis->offset);
1532 (void) printf("size:%d, endian:%s\n", dumpthis->size,
1533 dumpthis->big_endian ? "BIG" : "little");
1534 (void) printf("ino:%d, cpu:%d\n",
1535 dumpthis->intr_ino, dumpthis->intr_cpu);
1538 #ifdef STANDALONE
1540 /* Test program for this module. Useful when implementing new options. */
1542 main(int argc, char *argv[])
1544 int status;
1545 pcitool_uiargs_t parsed_args;
1547 status = get_commandline_args(argc, argv, &parsed_args);
1548 if (status) {
1549 (void) printf("Error getting command.\n");
1551 dump_struct(&parsed_args);
1553 return (SUCCESS);
1556 #endif /* STANDALONE */
1557 #endif /* DEBUG */