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