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