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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "volume_devconfig.h"
30
31 #include <string.h>
32 #include <ctype.h>
33 #include <meta.h>
34 #include "volume_nvpair.h"
35 #include "volume_error.h"
36 #include "volume_output.h"
37 #include "volume_string.h"
38
39 /*
40 * Methods which manipulate a devconfig_t struct
41 */
42
43 /*
44 * Constructor: Create a devconfig_t struct. This devconfig_t must be
45 * freed with free_devconfig().
46 *
47 * @param devconfig
48 * RETURN: a new devconfig_t
49 *
50 * @param type
51 * the type of devconfig_t to create
52 *
53 * @return 0
54 * if successful
55 *
56 * @return non-zero
57 * if an error occurred. Use get_error_string() to
58 * retrieve the associated error message.
59 */
60 int
new_devconfig(devconfig_t ** devconfig,component_type_t type)61 new_devconfig(
62 devconfig_t **devconfig,
63 component_type_t type)
64 {
65 int error;
66
67 *devconfig = (devconfig_t *)calloc(1, sizeof (devconfig_t));
68 if (*devconfig == NULL) {
69 volume_set_error(gettext("new_devconfig() calloc() failed\n"));
70 return (-1);
71 }
72
73 /* Create attribute list */
74 if ((error = nvlist_alloc(&((*devconfig)->attributes),
75 NV_UNIQUE_NAME_TYPE, 0)) != 0) {
76 volume_set_error(gettext("devconfig_t nvlist_alloc() failed\n"));
77 free_devconfig(*devconfig);
78 return (error);
79 }
80
81 if ((error = devconfig_set_type(*devconfig, type)) != 0) {
82 free_devconfig(*devconfig);
83 return (error);
84 }
85
86 return (0);
87 }
88
89 /*
90 * Free memory (recursively) allocated to a devconfig_t struct
91 *
92 * @param arg
93 * pointer to the devconfig_t to be freed
94 */
95 void
free_devconfig(void * arg)96 free_devconfig(
97 void *arg)
98 {
99 devconfig_t *devconfig = (devconfig_t *)arg;
100
101 if (devconfig == NULL) {
102 return;
103 }
104
105 /* Free the attributes nvlist */
106 if (devconfig->attributes != NULL) {
107 nvlist_free(devconfig->attributes);
108 }
109
110 /* Free available devices */
111 if (devconfig->available != NULL) {
112 free_string_array(devconfig->available);
113 }
114
115 /* Free unavailable devices */
116 if (devconfig->unavailable != NULL) {
117 free_string_array(devconfig->unavailable);
118 }
119
120 /* Free the components */
121 if (devconfig->components != NULL) {
122 dlist_free_items(devconfig->components, free_devconfig);
123 }
124
125 /* Free the devconfig itself */
126 free(devconfig);
127 }
128
129 /*
130 * Check the type of the given device.
131 *
132 * @param device
133 * the device whose type to check
134 *
135 * @param type
136 * the type of the device against which to compare
137 *
138 * @return B_TRUE if the device is of the given type, B_FALSE
139 * otherwise
140 */
141 boolean_t
devconfig_isA(devconfig_t * device,component_type_t type)142 devconfig_isA(
143 devconfig_t *device,
144 component_type_t type)
145 {
146 component_type_t curtype;
147
148 if (device == NULL) {
149 return (B_FALSE);
150 }
151
152 if (devconfig_get_type(device, &curtype) != 0) {
153 return (B_FALSE);
154 }
155
156 if (curtype != type) {
157 return (B_FALSE);
158 }
159
160 return (B_TRUE);
161 }
162
163 /*
164 * Get the first component of the given type from the given
165 * devconfig_t. Create the component if create is B_TRUE.
166 *
167 * @return ENOENT
168 * if the requested component does not exist and its
169 * creation was not requested
170 *
171 * @return 0
172 * if the requested component exists or was created
173 *
174 * @return non-zero
175 * if the requested component did not exist and could not
176 * be created
177 */
178 int
devconfig_get_component(devconfig_t * device,component_type_t type,devconfig_t ** component,boolean_t create)179 devconfig_get_component(
180 devconfig_t *device,
181 component_type_t type,
182 devconfig_t **component,
183 boolean_t create)
184 {
185 dlist_t *list;
186 int error = 0;
187 char *typestr = devconfig_type_to_str(type);
188
189 oprintf(OUTPUT_DEBUG, gettext("Searching for singleton %s\n"), typestr);
190
191 /* For each component of this device... */
192 for (list = devconfig_get_components(device);
193 list != NULL; list = list->next) {
194
195 *component = (devconfig_t *)list->obj;
196
197 /* Is this subcomponent an instance of the given type? */
198 if (*component != NULL && devconfig_isA(*component, type)) {
199 oprintf(OUTPUT_DEBUG, gettext("Found %s\n"), typestr);
200 return (0);
201 }
202 }
203
204 /* No component found */
205 error = ENOENT;
206 *component = NULL;
207
208 oprintf(OUTPUT_DEBUG, gettext("%s not found\n"), typestr);
209
210 if (create == B_TRUE) {
211 oprintf(OUTPUT_DEBUG, gettext("Creating %s\n"), typestr);
212
213 /*
214 * An existing singleton component of the given type was
215 * not found under the given disk set. So, create one.
216 */
217 if ((error = new_devconfig(component, type)) == 0) {
218 /* Attach new component to given device */
219 devconfig_set_components(
220 device, dlist_append(dlist_new_item(*component),
221 devconfig_get_components(device), AT_TAIL));
222 }
223 }
224
225 return (error);
226 }
227
228 /*
229 * Set the available devices for use in creating this device
230 *
231 * @param device
232 * a devconfig_t representing the device to modify
233 *
234 * @param available
235 * A NULL-terminated array of device names
236 */
237 void
devconfig_set_available(devconfig_t * device,char ** available)238 devconfig_set_available(
239 devconfig_t *device,
240 char **available)
241 {
242 device->available = available;
243 }
244
245 /*
246 * Get the available devices for use in creating this device
247 *
248 * @param device
249 * a devconfig_t representing the device to examine
250 *
251 * @return available
252 * A NULL-terminated array of device names
253 */
254 char **
devconfig_get_available(devconfig_t * device)255 devconfig_get_available(
256 devconfig_t *device)
257 {
258 return (device->available);
259 }
260
261 /*
262 * Set the unavailable devices which may not be used in creating this
263 * device
264 *
265 * @param device
266 * a devconfig_t representing the device to modify
267 *
268 * @param available
269 * A NULL-terminated array of device names
270 */
271 void
devconfig_set_unavailable(devconfig_t * device,char ** unavailable)272 devconfig_set_unavailable(
273 devconfig_t *device,
274 char **unavailable)
275 {
276 device->unavailable = unavailable;
277 }
278
279 /*
280 * Get the unavailable devices for use in creating this device
281 *
282 * @param device
283 * a devconfig_t representing the device to examine
284 *
285 * @return unavailable
286 * A NULL-terminated array of device names
287 */
288 char **
devconfig_get_unavailable(devconfig_t * device)289 devconfig_get_unavailable(
290 devconfig_t *device)
291 {
292 return (device->unavailable);
293 }
294
295 /*
296 * Set the subcomponent devices of a given device
297 *
298 * @param device
299 * a devconfig_t representing the device to examine
300 *
301 * @param components
302 * A dlist_t containing devconfig_t devices
303 */
304 void
devconfig_set_components(devconfig_t * device,dlist_t * components)305 devconfig_set_components(
306 devconfig_t *device,
307 dlist_t *components)
308 {
309 device->components = components;
310 }
311
312 /*
313 * Get the subcomponent devices of a given device
314 *
315 * @param device
316 * a devconfig_t representing the device to examine
317 *
318 * @return A dlist_t containing devconfig_t devices
319 */
320 dlist_t *
devconfig_get_components(devconfig_t * device)321 devconfig_get_components(
322 devconfig_t *device)
323 {
324 return (device->components);
325 }
326
327 /*
328 * Set the device name
329 *
330 * @param device
331 * a devconfig_t representing the device to modify
332 *
333 * @param name
334 * the value to set as the device name
335 *
336 * @return 0
337 * if successful
338 *
339 * @return non-zero
340 * if an error occurred. Use get_error_string() to
341 * retrieve the associated error message.
342 */
343 int
devconfig_set_name(devconfig_t * device,char * name)344 devconfig_set_name(
345 devconfig_t *device,
346 char *name)
347 {
348 return (set_string(device->attributes, ATTR_NAME, name));
349 }
350
351 /*
352 * Set the disk set name
353 *
354 * @param diskset
355 * a devconfig_t representing the diskset to modify
356 *
357 * @param name
358 * the value to set as the device name
359 *
360 * @return 0
361 * if successful
362 *
363 * @return non-zero
364 * if an error occurred. Use get_error_string() to
365 * retrieve the associated error message.
366 */
367 int
devconfig_set_diskset_name(devconfig_t * diskset,char * name)368 devconfig_set_diskset_name(
369 devconfig_t *diskset,
370 char *name)
371 {
372 md_error_t error = mdnullerror;
373
374 /* Verify syntax of disk set name */
375 if (meta_set_checkname(name, &error)) {
376 volume_set_error(gettext("invalid disk set name: %s"), name);
377 return (-1);
378 }
379
380 return (devconfig_set_name(diskset, name));
381 }
382
383 /*
384 * Set the device name
385 *
386 * @param hsp
387 * a devconfig_t representing the hsp to modify
388 *
389 * @param name
390 * the value to set as the device name
391 *
392 * @return 0
393 * if successful
394 *
395 * @return non-zero
396 * if an error occurred. Use get_error_string() to
397 * retrieve the associated error message.
398 */
399 int
devconfig_set_hsp_name(devconfig_t * hsp,char * name)400 devconfig_set_hsp_name(
401 devconfig_t *hsp,
402 char *name)
403 {
404 /* Validate name */
405 if (!is_hspname(name)) {
406 volume_set_error(gettext("invalid hot spare pool name: %s"), name);
407 return (-1);
408 }
409
410 return (devconfig_set_name(hsp, name));
411 }
412
413 /*
414 * Set the device name
415 *
416 * @param volume
417 * a devconfig_t representing the volume to modify
418 *
419 * @param name
420 * the value to set as the device name
421 *
422 * @return 0
423 * if successful
424 *
425 * @return non-zero
426 * if an error occurred. Use get_error_string() to
427 * retrieve the associated error message.
428 */
429 int
devconfig_set_volume_name(devconfig_t * volume,char * name)430 devconfig_set_volume_name(
431 devconfig_t *volume,
432 char *name)
433 {
434 /* Validate name */
435 if (!is_metaname(name)) {
436 volume_set_error(gettext("invalid volume name: %s"), name);
437 return (-1);
438 }
439
440 return (devconfig_set_name(volume, name));
441 }
442
443 /*
444 * Get the device name
445 *
446 * @param volume
447 * a devconfig_t representing the volume to examine
448 *
449 * @param name
450 * RETURN: the device name
451 *
452 * @return 0
453 * if successful
454 *
455 * @return non-zero
456 * if an error occurred. Use get_error_string() to
457 * retrieve the associated error message.
458 */
459 int
devconfig_get_name(devconfig_t * device,char ** name)460 devconfig_get_name(
461 devconfig_t *device,
462 char **name)
463 {
464 int error = get_string(device->attributes, ATTR_NAME, name);
465
466 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
467 if (error == ENOENT) {
468 volume_set_error(gettext("device name not set"));
469 error = ERR_ATTR_UNSET;
470 }
471
472 return (error);
473 }
474
475 /*
476 * Set the device type
477 *
478 * @param device
479 * a devconfig_t representing the device to modify
480 *
481 * @param type
482 * the value to set as the device type
483 *
484 * @return 0
485 * if successful
486 *
487 * @return non-zero
488 * if an error occurred. Use get_error_string() to
489 * retrieve the associated error message.
490 */
491 int
devconfig_set_type(devconfig_t * device,component_type_t type)492 devconfig_set_type(
493 devconfig_t *device,
494 component_type_t type)
495 {
496 return (set_uint16(device->attributes, ATTR_TYPE, (uint16_t)type));
497 }
498
499 /*
500 * Get the device type
501 *
502 * @param device
503 * a devconfig_t representing the device to examine
504 *
505 * @param type
506 * RETURN: the device type
507 *
508 * @return 0
509 * if successful
510 *
511 * @return non-zero
512 * if an error occurred. Use get_error_string() to
513 * retrieve the associated error message.
514 */
515 int
devconfig_get_type(devconfig_t * device,component_type_t * type)516 devconfig_get_type(
517 devconfig_t *device,
518 component_type_t *type)
519 {
520 uint16_t val;
521 int error = get_uint16(device->attributes, ATTR_TYPE, &val);
522
523 switch (error) {
524 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
525 case ENOENT:
526 volume_set_error(gettext("device type not set"));
527 error = ERR_ATTR_UNSET;
528 break;
529
530 /* Success */
531 case 0:
532 *type = (component_type_t)val;
533 }
534
535 return (error);
536 }
537
538 /*
539 * Set the device size (for volume, mirror, stripe, concat) in bytes
540 *
541 * Note that size in bytes in a 64-bit field cannot hold the size that
542 * can be accessed in a 16 byte CDB. Since CDBs operate on blocks,
543 * the max capacity is 2^73 bytes with 512 byte blocks.
544 *
545 * @param device
546 * a devconfig_t representing the device to modify
547 *
548 * @param size_in_bytes
549 * the value to set as the device size in bytes
550 *
551 * @return 0
552 * if successful
553 *
554 * @return non-zero
555 * if an error occurred. Use get_error_string() to
556 * retrieve the associated error message.
557 */
558 int
devconfig_set_size(devconfig_t * device,uint64_t size_in_bytes)559 devconfig_set_size(
560 devconfig_t *device,
561 uint64_t size_in_bytes)
562 {
563
564 /* Validate against limits */
565 /* LINTED -- MIN_SIZE may be 0 */
566 if (size_in_bytes < MIN_SIZE) {
567 volume_set_error(gettext("size (in bytes) too small: %llu"),
568 (unsigned long long)size_in_bytes);
569 return (-1);
570 }
571
572 return (set_uint64(device->attributes,
573 ATTR_SIZEINBYTES, size_in_bytes));
574 }
575
576 /*
577 * Get the device size (for volume, mirror, stripe, concat) in bytes
578 *
579 * Note that size in bytes in a 64-bit field cannot hold the size that
580 * can be accessed in a 16 byte CDB. Since CDBs operate on blocks,
581 * the max capacity is 2^73 bytes with 512 byte blocks.
582 *
583 * @param device
584 * a devconfig_t representing the device to examine
585 *
586 * @param size_in_bytes
587 * RETURN: the device size in bytes
588 *
589 * @return 0
590 * if successful
591 *
592 * @return non-zero
593 * if an error occurred. Use get_error_string() to
594 * retrieve the associated error message.
595 */
596 int
devconfig_get_size(devconfig_t * device,uint64_t * size_in_bytes)597 devconfig_get_size(
598 devconfig_t *device,
599 uint64_t *size_in_bytes)
600 {
601 int error = get_uint64(
602 device->attributes, ATTR_SIZEINBYTES, size_in_bytes);
603
604 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
605 if (error == ENOENT) {
606 volume_set_error(gettext("size (in bytes) not set"));
607 error = ERR_ATTR_UNSET;
608 }
609
610 return (error);
611 }
612
613 /*
614 * Set the device size in blocks
615 *
616 * @param device
617 * a devconfig_t representing the device to modify
618 *
619 * @param type
620 * the value to set as the device size in blocks
621 *
622 * @return 0
623 * if successful
624 *
625 * @return non-zero
626 * if an error occurred. Use get_error_string() to
627 * retrieve the associated error message.
628 */
629 int
devconfig_set_size_in_blocks(devconfig_t * device,uint64_t size_in_blocks)630 devconfig_set_size_in_blocks(
631 devconfig_t *device,
632 uint64_t size_in_blocks)
633 {
634 /* Validate against limits */
635 /* LINTED -- MIN_SIZE_IN_BLOCKS may be 0 */
636 if (size_in_blocks < MIN_SIZE_IN_BLOCKS) {
637 volume_set_error(gettext("size (in blocks) too small: %llu"),
638 (unsigned long long)size_in_blocks);
639 return (-1);
640 }
641
642 return (set_uint64(device->attributes,
643 ATTR_SIZEINBLOCKS, size_in_blocks));
644 }
645
646 /*
647 * Get the device size in blocks
648 *
649 * @param device
650 * a devconfig_t representing the device to examine
651 *
652 * @param size_in_blocks
653 * RETURN: the device size in blocks
654 *
655 * @return 0
656 * if successful
657 *
658 * @return non-zero
659 * if an error occurred. Use get_error_string() to
660 * retrieve the associated error message.
661 */
662 int
devconfig_get_size_in_blocks(devconfig_t * device,uint64_t * size_in_blocks)663 devconfig_get_size_in_blocks(
664 devconfig_t *device,
665 uint64_t *size_in_blocks)
666 {
667 int error = get_uint64(
668 device->attributes, ATTR_SIZEINBLOCKS, size_in_blocks);
669
670 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
671 if (error == ENOENT) {
672 volume_set_error(gettext("size (in blocks) not set"));
673 error = ERR_ATTR_UNSET;
674 }
675
676 return (error);
677 }
678
679 /*
680 * Set the the slice index
681 *
682 * @param slice
683 * a devconfig_t representing the slice to modify
684 *
685 * @param index
686 * the value to set as the the slice index
687 *
688 * @return 0
689 * if successful
690 *
691 * @return non-zero
692 * if an error occurred. Use get_error_string() to
693 * retrieve the associated error message.
694 */
695 int
devconfig_set_slice_index(devconfig_t * slice,uint16_t index)696 devconfig_set_slice_index(
697 devconfig_t *slice,
698 uint16_t index)
699 {
700 return (set_uint16(slice->attributes, ATTR_SLICE_INDEX, index));
701 }
702
703 /*
704 * Get the slice index
705 *
706 * @param device
707 * a devconfig_t representing the device to examine
708 *
709 * @param index
710 * RETURN: the slice index
711 *
712 * @return 0
713 * if successful
714 *
715 * @return non-zero
716 * if an error occurred. Use get_error_string() to
717 * retrieve the associated error message.
718 */
719 int
devconfig_get_slice_index(devconfig_t * slice,uint16_t * index)720 devconfig_get_slice_index(
721 devconfig_t *slice,
722 uint16_t *index)
723 {
724 int error = get_uint16(slice->attributes, ATTR_SLICE_INDEX, index);
725
726 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
727 if (error == ENOENT) {
728 volume_set_error(gettext("slice index not set"));
729 error = ERR_ATTR_UNSET;
730 }
731
732 return (error);
733 }
734
735 /*
736 * Set the the slice start block
737 *
738 * @param slice
739 * a devconfig_t representing the slice to modify
740 *
741 * @param start_block
742 * the value to set as the the slice start block
743 *
744 * @return 0
745 * if successful
746 *
747 * @return non-zero
748 * if an error occurred. Use get_error_string() to
749 * retrieve the associated error message.
750 */
751 int
devconfig_set_slice_start_block(devconfig_t * slice,uint64_t start_block)752 devconfig_set_slice_start_block(
753 devconfig_t *slice,
754 uint64_t start_block)
755 {
756 return (set_uint64(slice->attributes,
757 ATTR_SLICE_STARTSECTOR, start_block));
758 }
759
760 /*
761 * Get the slice start block
762 *
763 * @param device
764 * a devconfig_t representing the device to examine
765 *
766 * @param start_block
767 * RETURN: the slice start block
768 *
769 * @return 0
770 * if successful
771 *
772 * @return non-zero
773 * if an error occurred. Use get_error_string() to
774 * retrieve the associated error message.
775 */
776 int
devconfig_get_slice_start_block(devconfig_t * slice,uint64_t * start_block)777 devconfig_get_slice_start_block(
778 devconfig_t *slice,
779 uint64_t *start_block)
780 {
781 int error = get_uint64(
782 slice->attributes, ATTR_SLICE_STARTSECTOR, start_block);
783
784 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
785 if (error == ENOENT) {
786 volume_set_error(gettext("slice start block not set"));
787 error = ERR_ATTR_UNSET;
788 }
789
790 return (error);
791 }
792
793 /*
794 * Set the number of subcomponents in mirror
795 *
796 * @param mirror
797 * a devconfig_t representing the mirror to modify
798 *
799 * @param nsubs
800 * the value to set as the number of subcomponents in
801 * mirror
802 *
803 * @return 0
804 * if successful
805 *
806 * @return non-zero
807 * if an error occurred. Use get_error_string() to
808 * retrieve the associated error message.
809 */
810 int
devconfig_set_mirror_nsubs(devconfig_t * mirror,uint16_t nsubs)811 devconfig_set_mirror_nsubs(
812 devconfig_t *mirror,
813 uint16_t nsubs)
814 {
815 /* Validate against limits */
816 if (nsubs < 1 || nsubs > NMIRROR) {
817 volume_set_error(
818 gettext("number of submirrors (%d) out of valid range (%d-%d)"),
819 nsubs, 1, NMIRROR);
820 return (-1);
821 }
822
823 return (set_uint16(mirror->attributes, ATTR_MIRROR_NSUBMIRRORS, nsubs));
824 }
825
826 /*
827 * Get number of subcomponents in mirror
828 *
829 * @param device
830 * a devconfig_t representing the device to examine
831 *
832 * @param nsubs
833 * RETURN: number of subcomponents in mirror
834 *
835 * @return 0
836 * if successful
837 *
838 * @return non-zero
839 * if an error occurred. Use get_error_string() to
840 * retrieve the associated error message.
841 */
842 int
devconfig_get_mirror_nsubs(devconfig_t * mirror,uint16_t * nsubs)843 devconfig_get_mirror_nsubs(
844 devconfig_t *mirror,
845 uint16_t *nsubs)
846 {
847 int error = get_uint16(
848 mirror->attributes, ATTR_MIRROR_NSUBMIRRORS, nsubs);
849
850 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
851 if (error == ENOENT) {
852 volume_set_error(gettext("number or submirrors not set"));
853 error = ERR_ATTR_UNSET;
854 }
855
856 return (error);
857 }
858
859 /*
860 * Set the read strategy for mirror
861 *
862 * @param mirror
863 * a devconfig_t representing the mirror to modify
864 *
865 * @param read
866 * the value to set as the read strategy for mirror
867 *
868 * @return 0
869 * if successful
870 *
871 * @return non-zero
872 * if an error occurred. Use get_error_string() to
873 * retrieve the associated error message.
874 */
875 int
devconfig_set_mirror_read(devconfig_t * mirror,mirror_read_strategy_t read)876 devconfig_set_mirror_read(
877 devconfig_t *mirror,
878 mirror_read_strategy_t read)
879 {
880 return (set_uint16(mirror->attributes,
881 ATTR_MIRROR_READ, (uint16_t)read));
882 }
883
884 /*
885 * Get read strategy for mirror
886 *
887 * @param device
888 * a devconfig_t representing the device to examine
889 *
890 * @param read
891 * RETURN: read strategy for mirror
892 *
893 * @return 0
894 * if successful
895 *
896 * @return non-zero
897 * if an error occurred. Use get_error_string() to
898 * retrieve the associated error message.
899 */
900 int
devconfig_get_mirror_read(devconfig_t * mirror,mirror_read_strategy_t * read)901 devconfig_get_mirror_read(
902 devconfig_t *mirror,
903 mirror_read_strategy_t *read)
904 {
905 uint16_t val;
906 int error = get_uint16(mirror->attributes, ATTR_MIRROR_READ, &val);
907
908 switch (error) {
909 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
910 case ENOENT:
911 volume_set_error(gettext("mirror read strategy not set"));
912 error = ERR_ATTR_UNSET;
913 break;
914
915 /* Success */
916 case 0:
917 *read = (mirror_read_strategy_t)val;
918 }
919
920 return (error);
921 }
922
923 /*
924 * Set the write strategy for mirror
925 *
926 * @param mirror
927 * a devconfig_t representing the mirror to modify
928 *
929 * @param write
930 * the value to set as the write strategy for mirror
931 *
932 * @return 0
933 * if successful
934 *
935 * @return non-zero
936 * if an error occurred. Use get_error_string() to
937 * retrieve the associated error message.
938 */
939 int
devconfig_set_mirror_write(devconfig_t * mirror,mirror_write_strategy_t write)940 devconfig_set_mirror_write(
941 devconfig_t *mirror,
942 mirror_write_strategy_t write)
943 {
944 return (set_uint16(mirror->attributes,
945 ATTR_MIRROR_WRITE, (uint16_t)write));
946 }
947
948 /*
949 * Get write strategy for mirror
950 *
951 * @param device
952 * a devconfig_t representing the device to examine
953 *
954 * @param write
955 * RETURN: write strategy for mirror
956 *
957 * @return 0
958 * if successful
959 *
960 * @return non-zero
961 * if an error occurred. Use get_error_string() to
962 * retrieve the associated error message.
963 */
964 int
devconfig_get_mirror_write(devconfig_t * mirror,mirror_write_strategy_t * write)965 devconfig_get_mirror_write(
966 devconfig_t *mirror,
967 mirror_write_strategy_t *write)
968 {
969 uint16_t val;
970 int error = get_uint16(mirror->attributes, ATTR_MIRROR_WRITE, &val);
971
972 switch (error) {
973 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
974 case ENOENT:
975 volume_set_error(gettext("mirror write strategy not set"));
976 error = ERR_ATTR_UNSET;
977 break;
978
979 /* Success */
980 case 0:
981 *write = (mirror_write_strategy_t)val;
982 }
983
984 return (error);
985 }
986
987 /*
988 * Set the resync pass for mirror
989 *
990 * @param mirror
991 * a devconfig_t representing the mirror to modify
992 *
993 * @param pass
994 * the value to set as the resync pass for mirror
995 *
996 * @return 0
997 * if successful
998 *
999 * @return non-zero
1000 * if an error occurred. Use get_error_string() to
1001 * retrieve the associated error message.
1002 */
1003 int
devconfig_set_mirror_pass(devconfig_t * mirror,uint16_t pass)1004 devconfig_set_mirror_pass(
1005 devconfig_t *mirror,
1006 uint16_t pass)
1007 {
1008 /* Validate against max value */
1009 if (pass > MD_PASS_MAX) {
1010 volume_set_error(
1011 gettext("mirror pass number (%d) out of valid range (0-%d)"),
1012 pass, MD_PASS_MAX);
1013 return (-1);
1014 }
1015
1016 return (set_uint16(mirror->attributes, ATTR_MIRROR_PASSNUM, pass));
1017 }
1018
1019 /*
1020 * Get resync pass for mirror
1021 *
1022 * @param device
1023 * a devconfig_t representing the device to examine
1024 *
1025 * @param pass
1026 * RETURN: resync pass for mirror
1027 *
1028 * @return 0
1029 * if successful
1030 *
1031 * @return non-zero
1032 * if an error occurred. Use get_error_string() to
1033 * retrieve the associated error message.
1034 */
1035 int
devconfig_get_mirror_pass(devconfig_t * mirror,uint16_t * pass)1036 devconfig_get_mirror_pass(
1037 devconfig_t *mirror,
1038 uint16_t *pass)
1039 {
1040 int error = get_uint16(mirror->attributes, ATTR_MIRROR_PASSNUM, pass);
1041
1042 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1043 if (error == ENOENT) {
1044 volume_set_error(gettext("mirror pass number not set"));
1045 error = ERR_ATTR_UNSET;
1046 }
1047
1048 return (error);
1049 }
1050
1051 /*
1052 * Set the minimum number of components in stripe
1053 *
1054 * @param stripe
1055 * a devconfig_t representing the stripe to modify
1056 *
1057 * @param mincomp
1058 * the value to set as the minimum number of components
1059 * in stripe
1060 *
1061 * @return 0
1062 * if successful
1063 *
1064 * @return non-zero
1065 * if an error occurred. Use get_error_string() to
1066 * retrieve the associated error message.
1067 */
1068 int
devconfig_set_stripe_mincomp(devconfig_t * stripe,uint16_t mincomp)1069 devconfig_set_stripe_mincomp(
1070 devconfig_t *stripe,
1071 uint16_t mincomp)
1072 {
1073 /* Validate against minimum value */
1074 if (mincomp < MIN_NSTRIPE_COMP) {
1075 volume_set_error(gettext(
1076 "minimum stripe components (%d) below minimum allowable (%d)"),
1077 mincomp, MIN_NSTRIPE_COMP);
1078 return (-1);
1079 }
1080
1081 return (set_uint16(stripe->attributes, ATTR_STRIPE_MINCOMP, mincomp));
1082 }
1083
1084 /*
1085 * Get minimum number of components in stripe
1086 *
1087 * @param device
1088 * a devconfig_t representing the device to examine
1089 *
1090 * @param mincomp
1091 * RETURN: minimum number of components in stripe
1092 *
1093 * @return 0
1094 * if successful
1095 *
1096 * @return non-zero
1097 * if an error occurred. Use get_error_string() to
1098 * retrieve the associated error message.
1099 */
1100 int
devconfig_get_stripe_mincomp(devconfig_t * stripe,uint16_t * mincomp)1101 devconfig_get_stripe_mincomp(
1102 devconfig_t *stripe,
1103 uint16_t *mincomp)
1104 {
1105 int error = get_uint16(
1106 stripe->attributes, ATTR_STRIPE_MINCOMP, mincomp);
1107
1108 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1109 if (error == ENOENT) {
1110 volume_set_error(
1111 gettext("minimum number of stripe components not set"));
1112 error = ERR_ATTR_UNSET;
1113 }
1114
1115 return (error);
1116 }
1117
1118 /*
1119 * Set the maximum number of components in stripe
1120 *
1121 * @param stripe
1122 * a devconfig_t representing the stripe to modify
1123 *
1124 * @param maxcomp
1125 * the value to set as the maximum number of components
1126 * in stripe
1127 *
1128 * @return 0
1129 * if successful
1130 *
1131 * @return non-zero
1132 * if an error occurred. Use get_error_string() to
1133 * retrieve the associated error message.
1134 */
1135 int
devconfig_set_stripe_maxcomp(devconfig_t * stripe,uint16_t maxcomp)1136 devconfig_set_stripe_maxcomp(
1137 devconfig_t *stripe,
1138 uint16_t maxcomp)
1139 {
1140 /* Validate against minimum value */
1141 if (maxcomp < MIN_NSTRIPE_COMP) {
1142 volume_set_error(gettext(
1143 "maximum stripe components (%d) below minimum allowable (%d)"),
1144 maxcomp, MIN_NSTRIPE_COMP);
1145 return (-1);
1146 }
1147
1148 return (set_uint16(stripe->attributes, ATTR_STRIPE_MAXCOMP, maxcomp));
1149 }
1150
1151 /*
1152 * Get maximum number of components in stripe
1153 *
1154 * @param device
1155 * a devconfig_t representing the device to examine
1156 *
1157 * @param maxcomp
1158 * RETURN: maximum number of components in stripe
1159 *
1160 * @return 0
1161 * if successful
1162 *
1163 * @return non-zero
1164 * if an error occurred. Use get_error_string() to
1165 * retrieve the associated error message.
1166 */
1167 int
devconfig_get_stripe_maxcomp(devconfig_t * stripe,uint16_t * maxcomp)1168 devconfig_get_stripe_maxcomp(
1169 devconfig_t *stripe,
1170 uint16_t *maxcomp)
1171 {
1172 int error = get_uint16(
1173 stripe->attributes, ATTR_STRIPE_MAXCOMP, maxcomp);
1174
1175 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1176 if (error == ENOENT) {
1177 volume_set_error(
1178 gettext("maximum number of stripe components not set"));
1179 error = ERR_ATTR_UNSET;
1180 }
1181
1182 return (error);
1183 }
1184
1185 /*
1186 * Set the stripe interlace
1187 *
1188 * @param stripe
1189 * a devconfig_t representing the stripe to modify
1190 *
1191 * @param interlace
1192 * the value to set as the stripe interlace
1193 *
1194 * @return 0
1195 * if successful
1196 *
1197 * @return non-zero
1198 * if an error occurred. Use get_error_string() to
1199 * retrieve the associated error message.
1200 */
1201 int
devconfig_set_stripe_interlace(devconfig_t * stripe,uint64_t interlace)1202 devconfig_set_stripe_interlace(
1203 devconfig_t *stripe,
1204 uint64_t interlace)
1205 {
1206 if (interlace < MININTERLACE || interlace > MAXINTERLACE) {
1207 char *intstr = NULL;
1208 char *minstr = NULL;
1209 char *maxstr = NULL;
1210
1211 /* Get string representations of interlaces */
1212 bytes_to_sizestr(interlace, &intstr, universal_units, B_FALSE);
1213 bytes_to_sizestr(MININTERLACE, &minstr, universal_units, B_FALSE);
1214 bytes_to_sizestr(MAXINTERLACE, &maxstr, universal_units, B_FALSE);
1215
1216 volume_set_error(
1217 gettext("interlace (%s) out of valid range (%s - %s)"),
1218 intstr, minstr, maxstr);
1219
1220 free(intstr);
1221 free(minstr);
1222 free(maxstr);
1223
1224 return (-1);
1225 }
1226
1227 return (set_uint64(stripe->attributes,
1228 ATTR_STRIPE_INTERLACE, interlace));
1229 }
1230
1231 /*
1232 * Get stripe interlace
1233 *
1234 * @param device
1235 * a devconfig_t representing the device to examine
1236 *
1237 * @param interlace
1238 * RETURN: stripe interlace
1239 *
1240 * @return 0
1241 * if successful
1242 *
1243 * @return non-zero
1244 * if an error occurred. Use get_error_string() to
1245 * retrieve the associated error message.
1246 */
1247 int
devconfig_get_stripe_interlace(devconfig_t * stripe,uint64_t * interlace)1248 devconfig_get_stripe_interlace(
1249 devconfig_t *stripe,
1250 uint64_t *interlace)
1251 {
1252 int error = get_uint64(
1253 stripe->attributes, ATTR_STRIPE_INTERLACE, interlace);
1254
1255 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1256 if (error == ENOENT) {
1257 volume_set_error(gettext("stripe interlace not set"));
1258 error = ERR_ATTR_UNSET;
1259 }
1260
1261 return (error);
1262 }
1263
1264 /*
1265 * Set the redundancy level for a volume.
1266 *
1267 * @param volume
1268 * a devconfig_t representing the volume to modify
1269 *
1270 * @param rlevel
1271 * If 0, a stripe will be created. If > 0, a mirror with
1272 * this number of submirrors will be created.
1273 *
1274 * @return 0
1275 * if successful
1276 *
1277 * @return non-zero
1278 * if an error occurred. Use get_error_string() to
1279 * retrieve the associated error message.
1280 */
1281 int
devconfig_set_volume_redundancy_level(devconfig_t * volume,uint16_t rlevel)1282 devconfig_set_volume_redundancy_level(
1283 devconfig_t *volume,
1284 uint16_t rlevel)
1285 {
1286 /* Validate against limits */
1287 if (rlevel > NMIRROR) {
1288 volume_set_error(gettext(
1289 "volume redundancy level (%d) out of valid range (%d-%d)"),
1290 rlevel, 0, NMIRROR);
1291 return (-1);
1292 }
1293
1294 return (set_uint16(volume->attributes, ATTR_VOLUME_REDUNDANCY, rlevel));
1295 }
1296
1297 /*
1298 * Get the redundancy level for a volume.
1299 *
1300 * @param device
1301 * a devconfig_t representing the device to examine
1302 *
1303 * @param rlevel
1304 * RETURN: the redundancy level for a volume
1305 *
1306 * @return 0
1307 * if successful
1308 *
1309 * @return non-zero
1310 * if an error occurred. Use get_error_string() to
1311 * retrieve the associated error message.
1312 */
1313 int
devconfig_get_volume_redundancy_level(devconfig_t * volume,uint16_t * rlevel)1314 devconfig_get_volume_redundancy_level(
1315 devconfig_t *volume,
1316 uint16_t *rlevel)
1317 {
1318 int error = get_uint16(
1319 volume->attributes, ATTR_VOLUME_REDUNDANCY, rlevel);
1320
1321 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1322 if (error == ENOENT) {
1323 volume_set_error(gettext("volume redundancy level not set"));
1324 error = ERR_ATTR_UNSET;
1325 }
1326
1327 return (error);
1328 }
1329
1330 /*
1331 * Set the number of paths in volume
1332 *
1333 * @param volume
1334 * a devconfig_t representing the volume to modify
1335 *
1336 * @param npaths
1337 * the value to set as the number of paths in volume
1338 *
1339 * @return 0
1340 * if successful
1341 *
1342 * @return non-zero
1343 * if an error occurred. Use get_error_string() to
1344 * retrieve the associated error message.
1345 */
1346 int
devconfig_set_volume_npaths(devconfig_t * volume,uint16_t npaths)1347 devconfig_set_volume_npaths(
1348 devconfig_t *volume,
1349 uint16_t npaths)
1350 {
1351 /* Validate against limits */
1352 if (npaths < MIN_NDATAPATHS || npaths > MAX_NDATAPATHS) {
1353 volume_set_error(
1354 gettext("number of data paths (%d) out of valid range (%d-%d)"),
1355 npaths, MIN_NDATAPATHS, MAX_NDATAPATHS);
1356 return (-1);
1357 }
1358
1359 return (set_uint16(volume->attributes, ATTR_VOLUME_DATAPATHS, npaths));
1360 }
1361
1362 /*
1363 * Get number of paths in volume
1364 *
1365 * @param device
1366 * a devconfig_t representing the device to examine
1367 *
1368 * @param npaths
1369 * RETURN: number of paths in volume
1370 *
1371 * @return 0
1372 * if successful
1373 *
1374 * @return non-zero
1375 * if an error occurred. Use get_error_string() to
1376 * retrieve the associated error message.
1377 */
1378 int
devconfig_get_volume_npaths(devconfig_t * volume,uint16_t * npaths)1379 devconfig_get_volume_npaths(
1380 devconfig_t *volume,
1381 uint16_t *npaths)
1382 {
1383 int error = get_uint16(
1384 volume->attributes, ATTR_VOLUME_DATAPATHS, npaths);
1385
1386 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1387 if (error == ENOENT) {
1388 volume_set_error(gettext("number of data paths not set"));
1389 error = ERR_ATTR_UNSET;
1390 }
1391
1392 return (error);
1393 }
1394
1395 /*
1396 * Set the HSP creation option (for volume, stripe, concat, mirror)
1397 *
1398 * @param volume
1399 * a devconfig_t representing the volume to modify
1400 *
1401 * @param usehsp
1402 * the value to set as the HSP creation option
1403 *
1404 * @return 0
1405 * if successful
1406 *
1407 * @return non-zero
1408 * if an error occurred. Use get_error_string() to
1409 * retrieve the associated error message.
1410 */
1411 int
devconfig_set_volume_usehsp(devconfig_t * volume,boolean_t usehsp)1412 devconfig_set_volume_usehsp(
1413 devconfig_t *volume,
1414 boolean_t usehsp)
1415 {
1416 return (set_boolean(volume->attributes, ATTR_VOLUME_USEHSP, usehsp));
1417 }
1418
1419 /*
1420 * Get HSP creation option (for volume, stripe, concat, mirror)
1421 *
1422 * @param device
1423 * a devconfig_t representing the device to examine
1424 *
1425 * @param usehsp
1426 * RETURN: HSP creation option (for volume, stripe,
1427 * concat, mirror)
1428 *
1429 * @return 0
1430 * if successful
1431 *
1432 * @return non-zero
1433 * if an error occurred. Use get_error_string() to
1434 * retrieve the associated error message.
1435 */
1436 int
devconfig_get_volume_usehsp(devconfig_t * volume,boolean_t * usehsp)1437 devconfig_get_volume_usehsp(
1438 devconfig_t *volume,
1439 boolean_t *usehsp)
1440 {
1441 int error = get_boolean(
1442 volume->attributes, ATTR_VOLUME_USEHSP, usehsp);
1443
1444 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */
1445 if (error == ENOENT) {
1446 volume_set_error(gettext("volume usehsp not set"));
1447 error = ERR_ATTR_UNSET;
1448 }
1449
1450 return (error);
1451 }
1452
1453 /*
1454 * Get the string representation of the volume's type
1455 *
1456 * @param type
1457 * a valid component_type_t
1458 *
1459 * @return an internationalized string representing the given
1460 * type
1461 */
1462 char *
devconfig_type_to_str(component_type_t type)1463 devconfig_type_to_str(
1464 component_type_t type)
1465 {
1466 char *str;
1467
1468 switch (type) {
1469 case TYPE_CONCAT: str = gettext("Concat"); break;
1470 case TYPE_CONTROLLER: str = gettext("Controller"); break;
1471 case TYPE_DISKSET: str = gettext("Diskset"); break;
1472 case TYPE_DRIVE: str = gettext("Disk"); break;
1473 case TYPE_EXTENT: str = gettext("Extent"); break;
1474 case TYPE_HOST: str = gettext("Host"); break;
1475 case TYPE_HSP: str = gettext("Hot Spare Pool"); break;
1476 case TYPE_MIRROR: str = gettext("Mirror"); break;
1477 case TYPE_RAID5: str = gettext("Raid5"); break;
1478 case TYPE_SLICE: str = gettext("Slice"); break;
1479 case TYPE_SOFTPART: str = gettext("Soft Partition"); break;
1480 case TYPE_STRIPE: str = gettext("Stripe"); break;
1481 case TYPE_TRANS: str = gettext("Trans"); break;
1482 case TYPE_VOLUME: str = gettext("Volume"); break;
1483 default:
1484 case TYPE_UNKNOWN: str = gettext("Unknown"); break;
1485 }
1486
1487 return (str);
1488 }
1489
1490 /*
1491 * Get the string representation of the mirror's read strategy
1492 *
1493 * @param read
1494 * a valid mirror_read_strategy_t
1495 *
1496 * @return an internationalized string representing the given
1497 * read strategy
1498 */
1499 char *
devconfig_read_strategy_to_str(mirror_read_strategy_t read)1500 devconfig_read_strategy_to_str(
1501 mirror_read_strategy_t read)
1502 {
1503 char *str;
1504
1505 switch (read) {
1506 case MIRROR_READ_ROUNDROBIN: str = gettext("ROUNDROBIN"); break;
1507 case MIRROR_READ_GEOMETRIC: str = gettext("GEOMETRIC"); break;
1508 case MIRROR_READ_FIRST: str = gettext("FIRST"); break;
1509 default: str = "";
1510 }
1511
1512 return (str);
1513 }
1514
1515 /*
1516 * Get the string representation of the mirror's write strategy
1517 *
1518 * @param write
1519 * a valid mirror_write_strategy_t
1520 *
1521 * @return an internationalized string representing the given
1522 * write strategy
1523 */
1524 char *
devconfig_write_strategy_to_str(mirror_write_strategy_t write)1525 devconfig_write_strategy_to_str(
1526 mirror_write_strategy_t write)
1527 {
1528 char *str;
1529
1530 switch (write) {
1531 case MIRROR_WRITE_PARALLEL: str = gettext("PARALLEL"); break;
1532 case MIRROR_WRITE_SERIAL: str = gettext("SERIAL"); break;
1533 default: str = "";
1534 }
1535
1536 return (str);
1537 }
1538
1539 #ifdef DEBUG
1540 /*
1541 * Dump the contents of a devconfig_t struct to stdout.
1542 *
1543 * @param device
1544 * the devconfig_t to examine
1545 *
1546 * @param prefix
1547 * a prefix string to print before each line
1548 */
1549 void
devconfig_dump(devconfig_t * device,char * prefix)1550 devconfig_dump(
1551 devconfig_t *device,
1552 char *prefix)
1553 {
1554 dlist_t *comps = NULL;
1555 char **array = NULL;
1556 char *str = NULL;
1557 int i = 0;
1558
1559 component_type_t type = TYPE_UNKNOWN;
1560 boolean_t bool = B_FALSE;
1561 uint16_t val16 = 0;
1562 uint64_t val64 = 0;
1563 mirror_read_strategy_t read;
1564 mirror_write_strategy_t write;
1565
1566 if (device == NULL) {
1567 return;
1568 }
1569
1570 /* Type */
1571 if (devconfig_get_type(device, &type) == 0) {
1572 printf("%s%s\n", prefix, devconfig_type_to_str(type));
1573 }
1574
1575 /* Name */
1576 if (devconfig_get_name(device, &str) == 0) {
1577 printf("%s name: %s\n", prefix, str);
1578 }
1579
1580 /* Size in bytes */
1581 if (devconfig_get_size(device, &val64) == 0) {
1582 printf("%s size in bytes: %llu\n", prefix, val64);
1583 }
1584
1585 /* Size in blocks */
1586 if (devconfig_get_size_in_blocks(device, &val64) == 0) {
1587 printf("%s size in blocks: %llu\n", prefix, val64);
1588 }
1589
1590 /* Use HSP */
1591 if (devconfig_get_volume_usehsp(device, &bool) == 0) {
1592 printf("%s usehsp: %s\n", prefix, bool? "TRUE" : "FALSE");
1593 }
1594
1595 switch (type) {
1596 case TYPE_VOLUME:
1597 /* Volume rlevel */
1598 if (devconfig_get_volume_redundancy_level(
1599 device, &val16) == 0) {
1600 printf("%s volume redundancy level: %d\n", prefix, val16);
1601 }
1602
1603 /* Volume npaths */
1604 if (devconfig_get_volume_npaths(device, &val16) == 0) {
1605 printf("%s volume npaths: %d\n", prefix, val16);
1606 }
1607 break;
1608
1609 case TYPE_MIRROR:
1610
1611 /* Mirror nsubs */
1612 if (devconfig_get_mirror_nsubs(device, &val16) == 0) {
1613 printf("%s mirror nsubs: %d\n", prefix, val16);
1614 }
1615
1616 /* Mirror read */
1617 if (devconfig_get_mirror_read(device, &read) == 0) {
1618 printf("%s mirror read: %s\n", prefix,
1619 devconfig_read_strategy_to_str(read));
1620 }
1621
1622 /* Mirror write */
1623 if (devconfig_get_mirror_write(device, &write) == 0) {
1624 printf("%s mirror write: %s\n", prefix,
1625 devconfig_write_strategy_to_str(write));
1626 }
1627
1628 /* Mirror pass */
1629 if (devconfig_get_mirror_pass(device, &val16) == 0) {
1630 printf("%s mirror pass: %d\n", prefix, val16);
1631 }
1632 break;
1633
1634 case TYPE_STRIPE:
1635 /* Stripe mincomp */
1636 if (devconfig_get_stripe_mincomp(device, &val16) == 0) {
1637 printf("%s stripe mincomp: %d\n", prefix, val16);
1638 }
1639
1640 /* Stripe maxcomp */
1641 if (devconfig_get_stripe_maxcomp(device, &val16) == 0) {
1642 printf("%s stripe maxcomp: %d\n", prefix, val16);
1643 }
1644
1645 /* Stripe interlace */
1646 if (devconfig_get_stripe_interlace(device, &val64) == 0) {
1647 printf("%s stripe interlace: %lld\n", prefix, val64);
1648 }
1649 break;
1650
1651 case TYPE_SLICE:
1652 /* Slice index */
1653 if (devconfig_get_slice_index(device, &val16) == 0) {
1654 printf("%s slice index: %d\n", prefix, val16);
1655 }
1656
1657 /* Slice start block */
1658 if (devconfig_get_slice_start_block(device, &val64) == 0) {
1659 printf("%s slice start block: %llu\n", prefix, val64);
1660 }
1661 break;
1662 }
1663
1664 array = devconfig_get_available(device);
1665 if (array != NULL) {
1666 printf("%s available:\n", prefix);
1667 for (i = 0; array[i] != NULL; i++) {
1668 printf("%s %s\n", prefix, array[i]);
1669 }
1670 }
1671
1672 array = devconfig_get_unavailable(device);
1673 if (array != NULL) {
1674 printf("%s unavailable:\n", prefix);
1675 for (i = 0; array[i] != NULL; i++) {
1676 printf("%s %s\n", prefix, array[i]);
1677 }
1678 }
1679
1680 printf("\n");
1681
1682 comps = devconfig_get_components(device);
1683 if (comps != NULL) {
1684 char buf[128];
1685 snprintf(buf, 128, "%s%s", prefix, " ");
1686 for (; comps != NULL; comps = comps->next) {
1687 devconfig_dump((devconfig_t *)comps->obj, buf);
1688 }
1689 }
1690 }
1691 #endif /* DEBUG */
1692