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