xref: /illumos-gate/usr/src/cmd/pcitool/pcitool_ui.c (revision 30165b7f6753bc3d48c52319bed7ec7b3ea36b3c)
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2012 Milan Jurik. All rights reserved.
24  */
25 
26 /*
27  * This is the user interface module for the pcitool.  It checks commandline
28  * arguments and options and stores them in a pcitool_uiargs_t structure passed
29  * back to the rest of the program for processing.
30  *
31  * Please see pcitool_usage.c for a complete commandline description.
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/inttypes.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <strings.h>
41 #include <errno.h>
42 #include <sys/pci.h>
43 
44 #include <sys/pci_tools.h>
45 
46 #include "pcitool_ui.h"
47 
48 /*
49  * Uncomment the following for useful debugging / development options for this
50  * module only.
51  */
52 
53 /* #define	DEBUG	1		*/
54 /* #define	STANDALONE	1	*/
55 
56 #define		DEVNAME_START_PCI	"/pci"
57 #define		DEVNAME_START_NIU	"/niu"
58 
59 /* Default read/write size when -s not specified. */
60 #define	DEFAULT_SIZE	4
61 
62 /* For get_value64 */
63 #define	HEX_ONLY	B_TRUE
64 #define	BASE_BY_PREFIX	B_FALSE
65 
66 #define	BITS_PER_BYTE	8
67 
68 /*
69  * This defines which main options can be specified by the user.
70  * Options with colons after them require arguments.
71  */
72 static char *opt_string = ":n:d:i:m:p:rw:o:s:e:b:vaqlcxgy";
73 
74 /* This defines options used singly and only by themselves (no nexus). */
75 static char *no_dev_opt_string = "ahpqv";
76 
77 static void print_bad_option(char *argv[], int optopt, char *optarg);
78 static boolean_t get_confirmation(void);
79 static int get_value64(char *value_str, uint64_t *value, boolean_t hex_only);
80 static int parse_nexus_opts(char *input, uint64_t *flags_arg, uint8_t *bank_arg,
81     uint64_t *base_addr_arg);
82 static int extract_bdf_arg(char *cvalue, char *fld, uint64_t fld_flag,
83     uint64_t *all_flags, uint8_t *ivalue);
84 static int extract_bdf(char *value, char **bvalue_p, char **dvalue_p,
85     char **fvalue_p);
86 static int parse_device_opts(char *input, uint64_t *flags_arg,
87     uint8_t *bus_arg, uint8_t *device_arg, uint8_t *func_arg,
88     uint8_t *bank_arg);
89 static int parse_ino_opts(char *input, uint64_t *flags_arg,
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);
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_PCI) != argv[1]) &&
137 	    (strstr(argv[1], DEVNAME_START_NIU) != argv[1])) {
138 
139 		/* Default is to probe all trees accounting for bus ranges. */
140 		parsed_args->flags = PROBEALL_FLAG | PROBERNG_FLAG;
141 
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)) {
145 
146 			switch (c) {
147 
148 			/* Help requested. */
149 			case 'h':
150 				usage(argv[0]);
151 				parsed_args->flags = 0;
152 				return (SUCCESS);
153 
154 			case 'p':
155 				/* Take default probe mode */
156 				break;
157 
158 			case 'a':
159 				/*
160 				 * Enable display of ALL bus numbers.
161 				 *
162 				 * This takes precidence over PROBERNG as -a
163 				 * is explicitly specified.
164 				 */
165 				parsed_args->flags &= ~PROBERNG_FLAG;
166 				break;
167 
168 			case 'q':
169 				parsed_args->flags |= QUIET_FLAG;
170 				break;
171 
172 			/* Verbose mode for full probe. */
173 			case 'v':
174 				parsed_args->flags |= VERBOSE_FLAG;
175 				break;
176 
177 			default:
178 				error = B_TRUE;
179 				break;
180 			}
181 		}
182 
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;
188 		}
189 
190 		if (error) {
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 -m, "
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 			/* 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;
269 			}
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;
279 			}
280 			parsed_args->flags |= INTR_FLAG;
281 
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;
289 			}
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;
299 			}
300 
301 			/* Process -p with no dedicated options to it. */
302 			if (optarg[0] == '-') {
303 				optind--;
304 
305 				/* Probe given tree observing ranges */
306 				parsed_args->flags |=
307 				    (PROBETREE_FLAG | PROBERNG_FLAG);
308 				continue;
309 			}
310 
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 {
320 				/*
321 				 * parse_probeone_opts found options to
322 				 * set up bdf.
323 				 */
324 				parsed_args->flags |= PROBEDEV_FLAG;
325 			}
326 			break;
327 
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;
334 			}
335 
336 			parsed_args->flags &= ~PROBERNG_FLAG;
337 			break;
338 
339 		/* Read */
340 		case 'r':
341 			if (!(parsed_args->flags &
342 			    (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) {
343 				error = B_TRUE;
344 				break;
345 			}
346 
347 			/*
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.
352 			 */
353 			parsed_args->flags |= READ_FLAG;
354 			break;
355 
356 		/* Write */
357 		case 'w':
358 			if (!(parsed_args->flags &
359 			    (LEAF_FLAG | NEXUS_FLAG | INTR_FLAG))) {
360 				error = B_TRUE;
361 				break;
362 			}
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;
368 			}
369 
370 			/*
371 			 * For device and nexus, get a single register value
372 			 * to write.
373 			 */
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;
384 				}
385 
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;
397 				}
398 
399 			} else {
400 				error = B_TRUE;
401 				break;
402 			}
403 			break;
404 
405 		/* Offset */
406 		case 'o':
407 			if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
408 				error = B_TRUE;
409 				break;
410 			}
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;
416 			}
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;
423 			}
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;
430 			}
431 			break;
432 
433 		/* Size */
434 		case 's':
435 			if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
436 				error = B_TRUE;
437 				break;
438 			}
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;
444 			}
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;
451 			}
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;
463 			}
464 			parsed_args->size |= (uint8_t)recv64;
465 			break;
466 
467 		/* Endian. */
468 		case 'e':
469 			if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
470 				error = B_TRUE;
471 				break;
472 			}
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;
478 			}
479 			parsed_args->flags |= ENDIAN_FLAG;
480 
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;
487 			}
488 
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;
500 			}
501 			break;
502 
503 		/* (Byte)dump */
504 		case 'b':
505 			if (!(parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG))) {
506 				error = B_TRUE;
507 				break;
508 			}
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;
514 			}
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;
521 			}
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;
528 			}
529 			break;
530 
531 		/* Verbose. */
532 		case 'v':
533 			parsed_args->flags |= VERBOSE_FLAG;
534 			break;
535 
536 		/*
537 		 * Quiet - no errors reported as messages.
538 		 * (Status still returned by program, however.)
539 		 */
540 		case 'q':
541 			parsed_args->flags |= QUIET_FLAG;
542 			break;
543 
544 		/* Loop. */
545 		case 'l':
546 			parsed_args->flags |= LOOP_FLAG;
547 			break;
548 
549 		/*
550 		 * Dump characters with bytedump (-b).
551 		 * Show controller info with -i.
552 		 */
553 		case 'c':
554 			if (parsed_args->flags & BYTEDUMP_FLAG) {
555 				parsed_args->flags |= CHARDUMP_FLAG;
556 
557 			} else if (parsed_args->flags & INTR_FLAG) {
558 				parsed_args->flags |= SHOWCTLR_FLAG;
559 
560 			} else {
561 				error = B_TRUE;
562 			}
563 			break;
564 
565 		/* Continue on errors with bytedump (-b). */
566 		case 'x':
567 			if (!(parsed_args->flags & BYTEDUMP_FLAG)) {
568 				error = B_TRUE;
569 				break;
570 			}
571 			parsed_args->flags |= ERRCONT_FLAG;
572 			break;
573 
574 		case 'g':
575 			if (!(parsed_args->flags & INTR_FLAG)) {
576 				error = B_TRUE;
577 				break;
578 			}
579 			parsed_args->flags |= SETGRP_FLAG;
580 			break;
581 
582 		/* Take -y as confirmation and don't ask (where applicable). */
583 		case 'y':
584 			confirm = B_TRUE;
585 			break;
586 
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;
598 			}
599 			break;
600 
601 		/* Unrecognized option. */
602 		case '?':
603 			error = B_TRUE;
604 			break;
605 		}
606 	}
607 
608 	/*
609 	 * Commandline has been parsed.  Check for errors which can be checked
610 	 * only after commandline parsing is complete.
611 	 */
612 
613 	if (!error) {
614 
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);
621 		}
622 
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);
629 		}
630 
631 		/*
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.
635 		 */
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;
640 		}
641 
642 		/*
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.
646 		 */
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;
657 			}
658 
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;
669 			}
670 
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;
679 			}
680 
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;
688 			}
689 
690 			/*
691 			 * Disallow read & write together in interrupt command.
692 			 */
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;
699 			}
700 		}
701 
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;
710 		}
711 
712 		if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) {
713 
714 			if (!(parsed_args->flags & SIZE_FLAG)) {
715 				parsed_args->size = DEFAULT_SIZE;
716 			}
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;
725 			}
726 
727 		} else { /* Looping is compatible only with register cmds. */
728 
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;
733 			}
734 		}
735 
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]);
741 		}
742 	}
743 
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;
748 		}
749 
750 		if (parsed_args->flags & (LEAF_FLAG | NEXUS_FLAG)) {
751 			if (!(parsed_args->flags & ENDIAN_FLAG)) {
752 				parsed_args->big_endian = B_FALSE;
753 			}
754 		}
755 
756 		if (parsed_args->flags & BASE_SPEC_FLAG) {
757 			if (!confirm) {
758 				confirm = get_confirmation();
759 			}
760 			if (!confirm) {
761 				parsed_args->flags &= ~ALL_COMMANDS;
762 			}
763 		}
764 
765 		/*
766 		 * As far as other defaults are concerned:
767 		 *   Other fields: bus, device, function, offset, default to
768 		 *   zero.
769 		 */
770 
771 	} else {	/* An error occurred. */
772 
773 		print_bad_option(argv, optopt, optarg);
774 	}
775 	return (error);
776 }
777 
778 
779 /* Module-private functions. */
780 
781 static void
782 print_bad_option(char *argv[], int optopt, char *optarg)
783 {
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);
789 
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);
795 
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);
801 	}
802 
803 	(void) fprintf(stderr,
804 	    "%s: Type \"%s -h\" to get help on running this program.\n",
805 	    argv[0], argv[0]);
806 }
807 
808 /*
809  * Warn the user and ask for confirmation.
810  */
811 static boolean_t
812 get_confirmation()
813 {
814 	int i, b;
815 
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);
829 		}
830 	}
831 }
832 
833 
834 /*
835  * Given a digit string, return a 64 bit value.
836  *
837  * If the hex_only arg is true, interpret all strings as hex.
838  * Otherwise, interpret as strtoull(3C) does with base=0.
839  */
840 static int
841 get_value64(char *value_str, uint64_t *value, boolean_t hex_only)
842 {
843 
844 	/* This is overkill for now, as everything is in hex. */
845 	static char dec_digits[] = "0123456789";
846 	static char hex_digits[] = "01234567890abcdefABCDEF";
847 	static char oct_digits[] = "01234567";
848 
849 	char *digit_string;
850 	char *string_to_check;
851 
852 	if ((value_str == NULL) || (strlen(value_str) == 0)) {
853 		(void) fprintf(stderr, "Missing value argument.\n");
854 		return (FAILURE);
855 	}
856 
857 	if (!hex_only && (value_str[0] != '0')) {
858 		digit_string = dec_digits;
859 		string_to_check = value_str;
860 	} else if ((value_str[1] == 'X') || (value_str[1] == 'x')) {
861 		digit_string = hex_digits;
862 		string_to_check = &value_str[2];	/* Ignore 0x of hex */
863 	} else if (hex_only) {
864 		digit_string = hex_digits;
865 		string_to_check = value_str;	/* Hex number, no 0x prefix */
866 	} else {
867 		digit_string = oct_digits;
868 		string_to_check = value_str;
869 	}
870 
871 	/*
872 	 * Verify value is all proper digits.
873 	 *
874 	 * For some reason, strtoull doesn't return an error when it cannot
875 	 * interpret the value.  This is why we do the checking ourselves.
876 	 */
877 	if (strspn(string_to_check, digit_string) != strlen(string_to_check)) {
878 		(void) fprintf(stderr,
879 		    "Value must contain only valid digits.\n");
880 		return (FAILURE);
881 	}
882 
883 	*value = strtoull(value_str, NULL, (hex_only ? 16 : 0));
884 
885 	return (SUCCESS);
886 }
887 
888 
889 /*
890  * Parse nexus options.  This includes:
891  *   bank=number
892  *
893  * input is what the user specified for the options on the commandline,
894  * flags_arg is modified with the option set, and bank_arg returns the value
895  * specified for bank.
896  */
897 static int
898 parse_nexus_opts(char *input, uint64_t *flags_arg, uint8_t *bank_arg,
899     uint64_t *base_addr_arg)
900 {
901 	enum nexus_opts_index {
902 		bank = 0,
903 		base
904 	};
905 
906 	static char *nexus_opts[] = {
907 		"bank",
908 		"base",
909 		NULL
910 	};
911 
912 	char *value;
913 	uint64_t	recv64;
914 
915 	int rval = SUCCESS;
916 
917 	if (input == NULL) {
918 		(void) fprintf(stderr, "Missing argument.\n");
919 		return (FAILURE);
920 	}
921 
922 	while ((*input != '\0') && (rval == SUCCESS)) {
923 		switch (getsubopt(&input, nexus_opts, &value)) {
924 		case bank:
925 			if (*flags_arg & BANK_SPEC_FLAG) {
926 				(void) fprintf(stderr, "The bank or bar arg is "
927 				    "specified more than once.\n");
928 				rval = FAILURE;
929 				break;
930 			}
931 			if (*flags_arg & BASE_SPEC_FLAG) {
932 				(void) fprintf(stderr, "Bank and base address "
933 				    "cannot both be specified.\n");
934 				rval = FAILURE;
935 				break;
936 			}
937 			if (value == NULL) {
938 				(void) fprintf(stderr, "Missing bank value.\n");
939 				rval = FAILURE;
940 				break;
941 			}
942 			if ((rval = get_value64(value, &recv64, HEX_ONLY)) !=
943 			    SUCCESS) {
944 				break;
945 			}
946 			*bank_arg = (uint8_t)recv64;
947 			if (*bank_arg != recv64) {
948 				(void) fprintf(stderr,
949 				    "Bank argument must fit into 8 bits.\n");
950 				rval = FAILURE;
951 				break;
952 			}
953 			*flags_arg |= BANK_SPEC_FLAG;
954 			break;
955 
956 		case base:
957 			if (*flags_arg & BASE_SPEC_FLAG) {
958 				(void) fprintf(stderr, "The base address "
959 				    "is specified more than once.\n");
960 				rval = FAILURE;
961 				break;
962 			}
963 			if (*flags_arg & BANK_SPEC_FLAG) {
964 				(void) fprintf(stderr, "Bank and base address "
965 				    "cannot both be specified.\n");
966 				rval = FAILURE;
967 				break;
968 			}
969 			if (value == NULL) {
970 				(void) fprintf(stderr,
971 				    "Missing base addr value.\n");
972 				rval = FAILURE;
973 				break;
974 			}
975 			if ((rval = get_value64(value, base_addr_arg,
976 			    HEX_ONLY)) != SUCCESS) {
977 				break;
978 			}
979 			*flags_arg |= BASE_SPEC_FLAG;
980 			break;
981 
982 		default:
983 			(void) fprintf(stderr, "Unrecognized option for -n\n");
984 			rval = FAILURE;
985 			break;
986 		}
987 	}
988 
989 	return (rval);
990 }
991 
992 
993 static int
994 extract_bdf_arg(char *cvalue, char *fld, uint64_t fld_flag, uint64_t *all_flags,
995     uint8_t *ivalue)
996 {
997 	uint64_t recv64;
998 
999 	if (*all_flags & fld_flag) {
1000 		(void) fprintf(stderr,
1001 		    "The %s is specified more than once.\n", fld);
1002 		return (FAILURE);
1003 	}
1004 	if (get_value64(cvalue, &recv64, HEX_ONLY) != SUCCESS)
1005 		return (FAILURE);
1006 
1007 	*ivalue = (uint8_t)recv64;
1008 	if (recv64 != *ivalue) {
1009 		(void) fprintf(stderr,
1010 		    "This program limits the %s argument to 8 bits.\n", fld);
1011 		(void) fprintf(stderr, "The actual maximum may be "
1012 		    "smaller but cannot be enforced by this program.\n");
1013 		return (FAILURE);
1014 	}
1015 
1016 	*all_flags |= fld_flag;
1017 	return (SUCCESS);
1018 }
1019 
1020 
1021 static int extract_bdf(char *value, char **bvalue_p, char **dvalue_p,
1022     char **fvalue_p)
1023 {
1024 	char *strtok_state;
1025 	char *dummy;
1026 	static char *separator = ".";
1027 
1028 	*bvalue_p = strtok_r(value, separator, &strtok_state);
1029 	*dvalue_p = strtok_r(NULL, separator, &strtok_state);
1030 	*fvalue_p = strtok_r(NULL, separator, &strtok_state);
1031 	dummy = strtok_r(NULL, separator, &strtok_state);
1032 
1033 	/* Return failure only if too many values specified. */
1034 	return ((dummy) ? FAILURE : SUCCESS);
1035 }
1036 
1037 /*
1038  * Parse device options.  This includes:
1039  *   bus=number
1040  *   dev=number
1041  *   func=number
1042  *   bank=number
1043  *   config
1044  *   bar0
1045  *   bar1
1046  *   bar2
1047  *   bar3
1048  *   bar4
1049  *   bar5
1050  *   rom
1051  *
1052  * input is what the user specified for the options on the commandline,
1053  * flags_arg is modified with the options set, and the rest of the args return
1054  * their respective values.
1055  */
1056 static int
1057 parse_device_opts(
1058     char *input, uint64_t *flags_arg, uint8_t *bus_arg, uint8_t *device_arg,
1059     uint8_t *func_arg, uint8_t *bank_arg)
1060 {
1061 	/* Needed by getsubopt(3C) */
1062 	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
1076 	};
1077 
1078 	/* Needed by getsubopt(3C) */
1079 	static char *bdf_opts[] = {
1080 		"bus",
1081 		"dev",
1082 		"func",
1083 		"bdf",
1084 		"bank",
1085 		"config",
1086 		"bar0",
1087 		"bar1",
1088 		"bar2",
1089 		"bar3",
1090 		"bar4",
1091 		"bar5",
1092 		"rom",
1093 		NULL };
1094 
1095 	char *value;		/* Current suboption being processed. */
1096 	uint64_t recv64;	/* Temporary value. */
1097 
1098 	/* This error message is used in many places. */
1099 	static char bank_err[] =
1100 	    {"The bank or bar arg is specified more than once.\n"};
1101 
1102 	int rval = SUCCESS;
1103 
1104 	while ((*input != '\0') && (rval == SUCCESS)) {
1105 		switch (getsubopt(&input, bdf_opts, &value)) {
1106 
1107 		/* bus=number */
1108 		case bdf: {
1109 			char *bvalue, *dvalue, *fvalue;
1110 
1111 			if ((rval = extract_bdf(value, &bvalue, &dvalue,
1112 			    &fvalue)) != SUCCESS) {
1113 				break;
1114 			}
1115 
1116 			if (!bvalue | !dvalue | !fvalue) {
1117 				break;
1118 			}
1119 
1120 			if ((rval = extract_bdf_arg(bvalue, "bus",
1121 			    BUS_SPEC_FLAG, flags_arg, bus_arg)) != SUCCESS) {
1122 				break;
1123 			}
1124 			if ((rval = extract_bdf_arg(dvalue, "dev",
1125 			    DEV_SPEC_FLAG, flags_arg, device_arg)) != SUCCESS) {
1126 				break;
1127 			}
1128 			rval = extract_bdf_arg(fvalue, "func",
1129 			    FUNC_SPEC_FLAG, flags_arg, func_arg);
1130 			break;
1131 		}
1132 
1133 		case bus:
1134 			rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG,
1135 			    flags_arg, bus_arg);
1136 			break;
1137 
1138 		/* dev=number */
1139 		case dev:
1140 			rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG,
1141 			    flags_arg, device_arg);
1142 			break;
1143 
1144 		/* func=number */
1145 		case func:
1146 			rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG,
1147 			    flags_arg, func_arg);
1148 			break;
1149 
1150 		/* bank=number */
1151 		case bank:
1152 			if (*flags_arg & BANK_SPEC_FLAG) {
1153 				(void) fprintf(stderr, bank_err);
1154 				rval = FAILURE;
1155 				break;
1156 			}
1157 			if ((rval = get_value64(value, &recv64, HEX_ONLY)) !=
1158 			    SUCCESS) {
1159 				break;
1160 			}
1161 			*bank_arg = (uint8_t)recv64;
1162 			if (rval || (*bank_arg != recv64)) {
1163 				(void) fprintf(stderr, "Bank argument must"
1164 				    " fit into 8 bits.\n");
1165 				rval = FAILURE;
1166 				break;
1167 			}
1168 			*flags_arg |= BANK_SPEC_FLAG;
1169 			break;
1170 
1171 		/* config */
1172 		case config:
1173 			if (*flags_arg & BANK_SPEC_FLAG) {
1174 				(void) fprintf(stderr, bank_err);
1175 				rval = FAILURE;
1176 				break;
1177 			}
1178 			*bank_arg = PCITOOL_CONFIG;
1179 			*flags_arg |= BANK_SPEC_FLAG;
1180 			break;
1181 
1182 		/* bar0 */
1183 		case bar0:
1184 			if (*flags_arg & BANK_SPEC_FLAG) {
1185 				(void) fprintf(stderr, bank_err);
1186 				rval = FAILURE;
1187 				break;
1188 			}
1189 			*bank_arg = PCITOOL_BAR0;
1190 			*flags_arg |= BANK_SPEC_FLAG;
1191 			break;
1192 
1193 		/* bar1 */
1194 		case bar1:
1195 			if (*flags_arg & BANK_SPEC_FLAG) {
1196 				(void) fprintf(stderr, bank_err);
1197 				rval = FAILURE;
1198 				break;
1199 			}
1200 			*bank_arg = PCITOOL_BAR1;
1201 			*flags_arg |= BANK_SPEC_FLAG;
1202 			break;
1203 
1204 		/* bar2 */
1205 		case bar2:
1206 			if (*flags_arg & BANK_SPEC_FLAG) {
1207 				(void) fprintf(stderr, bank_err);
1208 				rval = FAILURE;
1209 				break;
1210 			}
1211 			*bank_arg = PCITOOL_BAR2;
1212 			*flags_arg |= BANK_SPEC_FLAG;
1213 			break;
1214 
1215 		/* bar3 */
1216 		case bar3:
1217 			if (*flags_arg & BANK_SPEC_FLAG) {
1218 				(void) fprintf(stderr, bank_err);
1219 				rval = FAILURE;
1220 				break;
1221 			}
1222 			*bank_arg = PCITOOL_BAR3;
1223 			*flags_arg |= BANK_SPEC_FLAG;
1224 			break;
1225 
1226 		/* bar4 */
1227 		case bar4:
1228 			if (*flags_arg & BANK_SPEC_FLAG) {
1229 				(void) fprintf(stderr, bank_err);
1230 				rval = FAILURE;
1231 				break;
1232 			}
1233 			*bank_arg = PCITOOL_BAR4;
1234 			*flags_arg |= BANK_SPEC_FLAG;
1235 			break;
1236 
1237 		/* bar5 */
1238 		case bar5:
1239 			if (*flags_arg & BANK_SPEC_FLAG) {
1240 				(void) fprintf(stderr, bank_err);
1241 				rval = FAILURE;
1242 				break;
1243 			}
1244 			*bank_arg = PCITOOL_BAR5;
1245 			*flags_arg |= BANK_SPEC_FLAG;
1246 			break;
1247 
1248 		/* rom */
1249 		case rom:
1250 			if (*flags_arg & BANK_SPEC_FLAG) {
1251 				(void) fprintf(stderr, bank_err);
1252 				rval = FAILURE;
1253 				break;
1254 			}
1255 			*bank_arg = PCITOOL_ROM;
1256 			*flags_arg |= BANK_SPEC_FLAG;
1257 			break;
1258 
1259 		default:
1260 			(void) fprintf(stderr, "Unrecognized option for -d\n");
1261 			rval = FAILURE;
1262 			break;
1263 		}
1264 	}
1265 
1266 	/* Bus, dev and func must all be specified. */
1267 	if ((*flags_arg & (BUS_SPEC_FLAG | DEV_SPEC_FLAG | FUNC_SPEC_FLAG)) !=
1268 	    (BUS_SPEC_FLAG | DEV_SPEC_FLAG | FUNC_SPEC_FLAG)) {
1269 		rval = FAILURE;
1270 
1271 	/* No bank specified in any way.  Default to config space */
1272 	} else if ((*flags_arg & BANK_SPEC_FLAG) == 0) {
1273 		*flags_arg |= BANK_SPEC_FLAG;
1274 		*bank_arg = PCITOOL_CONFIG;
1275 	}
1276 
1277 	return (rval);
1278 }
1279 
1280 
1281 /*
1282  * Parse INO options.  This includes:
1283  *   ino#  | all
1284  *
1285  * input is the string of options to parse.  flags_arg returns modified with
1286  * specified options set.  Other args return their respective values.
1287  */
1288 static int
1289 parse_ino_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg,
1290     uint8_t *ino_arg)
1291 {
1292 	uint64_t	value;
1293 	char		*charvalue;
1294 	int		rval = SUCCESS;
1295 
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;
1307 
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;
1314 		}
1315 #endif
1316 	} else if (charvalue = strtok(input, ",")) {
1317 		if ((rval =
1318 		    get_value64(charvalue, &value, HEX_ONLY)) == SUCCESS) {
1319 			*cpu_arg = (int)value;
1320 		}
1321 
1322 		input = strtok(NULL, ",");
1323 		if (input == NULL) {
1324 			(void) fprintf(stderr, "ino argument is need.\n");
1325 			return (FAILURE);
1326 		}
1327 
1328 		if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1329 			*ino_arg = (uint8_t)value;
1330 
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;
1337 		}
1338 	} else {
1339 		(void) fprintf(stderr,
1340 		    "Unrecognized option for -i\n");
1341 		rval = FAILURE;
1342 	}
1343 
1344 	return (rval);
1345 }
1346 
1347 
1348 /*
1349  * Parse MSI options.  This includes:
1350  *   msi#  | all
1351  *
1352  * input is the string of options to parse.  flags_arg returns modified with
1353  * specified options set.  Other args return their respective values.
1354  */
1355 static int
1356 parse_msi_opts(char *input, uint64_t *flags_arg, uint16_t *msi_arg)
1357 {
1358 	uint64_t	value;
1359 	int		rval = SUCCESS;
1360 
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;
1366 
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;
1373 		}
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);
1379 		}
1380 
1381 		if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS)
1382 			*msi_arg = (uint16_t)value;
1383 
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;
1390 		}
1391 	} else {
1392 		(void) fprintf(stderr,
1393 		    "Unrecognized option for -m\n");
1394 		rval = FAILURE;
1395 	}
1396 
1397 	return (rval);
1398 }
1399 
1400 
1401 /*
1402  * Parse interrupt set options.  This includes:
1403  *   cpu=number
1404  *
1405  * input is the string of options to parse.  flags_arg returns modified with
1406  * specified options set.  Other args return their respective values.
1407  */
1408 static int
1409 parse_intr_set_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg)
1410 {
1411 	uint64_t	value;
1412 	int		rval = SUCCESS;
1413 
1414 	if ((rval = get_value64(input, &value, HEX_ONLY)) == SUCCESS) {
1415 
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;
1423 		}
1424 	} else {
1425 		(void) fprintf(stderr,
1426 		    "Unrecognized option for -i -m -w\n");
1427 			rval = FAILURE;
1428 	}
1429 
1430 	return (rval);
1431 }
1432 
1433 
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)
1438 {
1439 	enum p1_bdf_opts_index {
1440 		bus = 0,
1441 		dev = 1,
1442 		func = 2,
1443 		bdf = 3
1444 	};
1445 
1446 	/* Needed by getsubopt(3C) */
1447 	static char *p1_bdf_opts[] = {
1448 		"bus",
1449 		"dev",
1450 		"func",
1451 		"bdf",
1452 		NULL };
1453 
1454 	char *value;		/* Current suboption being processed. */
1455 
1456 	int rval = SUCCESS;
1457 
1458 	while ((*input != '\0') && (rval == SUCCESS)) {
1459 		switch (getsubopt(&input, p1_bdf_opts, &value)) {
1460 
1461 		/* bus=number */
1462 		case bdf: {
1463 			char *bvalue, *dvalue, *fvalue;
1464 
1465 			if ((rval = extract_bdf(value, &bvalue, &dvalue,
1466 			    &fvalue)) != SUCCESS) {
1467 				break;
1468 			}
1469 			if (bvalue)
1470 				if ((rval = extract_bdf_arg(bvalue, "bus",
1471 				    BUS_SPEC_FLAG, flags_arg, bus_arg)) !=
1472 				    SUCCESS) {
1473 					break;
1474 				}
1475 			if (dvalue)
1476 				if ((rval = extract_bdf_arg(dvalue, "dev",
1477 				    DEV_SPEC_FLAG, flags_arg, device_arg)) !=
1478 				    SUCCESS) {
1479 				break;
1480 			}
1481 			if (fvalue)
1482 				rval = extract_bdf_arg(fvalue, "func",
1483 				    FUNC_SPEC_FLAG, flags_arg, func_arg);
1484 			break;
1485 		}
1486 
1487 		case bus:
1488 			rval = extract_bdf_arg(value, "bus", BUS_SPEC_FLAG,
1489 			    flags_arg, bus_arg);
1490 			break;
1491 
1492 		/* dev=number */
1493 		case dev:
1494 			rval = extract_bdf_arg(value, "dev", DEV_SPEC_FLAG,
1495 			    flags_arg, device_arg);
1496 			break;
1497 
1498 		/* func=number */
1499 		case func:
1500 			rval = extract_bdf_arg(value, "func", FUNC_SPEC_FLAG,
1501 			    flags_arg, func_arg);
1502 			break;
1503 
1504 		default:
1505 			(void) fprintf(stderr, "Unrecognized option for -p\n");
1506 			rval = FAILURE;
1507 			break;
1508 		}
1509 	}
1510 
1511 	return (rval);
1512 }
1513 
1514 
1515 #ifdef DEBUG
1516 
1517 static void
1518 dump_struct(pcitool_uiargs_t *dumpthis)
1519 {
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);
1536 }
1537 
1538 #ifdef STANDALONE
1539 
1540 /* Test program for this module.  Useful when implementing new options. */
1541 int
1542 main(int argc, char *argv[])
1543 {
1544 	int status;
1545 	pcitool_uiargs_t parsed_args;
1546 
1547 	status = get_commandline_args(argc, argv, &parsed_args);
1548 	if (status) {
1549 		(void) printf("Error getting command.\n");
1550 	}
1551 	dump_struct(&parsed_args);
1552 
1553 	return (SUCCESS);
1554 }
1555 
1556 #endif	/* STANDALONE */
1557 #endif	/* DEBUG */
1558