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