xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_discovery.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 2004 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 <limits.h>
30 #include <libdiskmgt.h>
31 #include <libintl.h>
32 
33 #include <meta.h>
34 
35 #define	_LAYOUT_DISCOVERY_C
36 
37 #include "volume_dlist.h"
38 #include "volume_error.h"
39 #include "volume_nvpair.h"
40 #include "volume_output.h"
41 
42 #include "layout_device_cache.h"
43 #include "layout_device_util.h"
44 #include "layout_dlist_util.h"
45 #include "layout_discovery.h"
46 #include "layout_request.h"
47 #include "layout_slice.h"
48 #include "layout_svm_util.h"
49 
50 /*
51  * lists of device dm_descriptor_t handles discovered during
52  * the initial system probe.  Lists are populated by
53  * discover_known_devices.
54  *
55  * "bad" slices are those that are known to libdiskmgt but
56  * cannot be accessed. An example would be a slice that has
57  * disappeared due to disk re-slicing: libdiskmgt may have a
58  * cached handle for it, but the slice no longer exists.
59  *
60  * "bad" disks are thoese that are known to libdiskmgt but
61  * cannot be accessed.  An example would be a disk that has
62  * failed or has gone offline: libdiskmgt may have a cached
63  * handle for it, but the disk does not respond.
64  */
65 static dlist_t	*_bad_slices = NULL;
66 static dlist_t	*_bad_disks = NULL;
67 
68 static dlist_t	*_known_slices = NULL;
69 static dlist_t	*_known_disks = NULL;
70 static dlist_t	*_known_hbas = NULL;
71 
72 /*
73  * helper functions for building known device lists, used by
74  * discover_known_devices.
75  */
76 static int generate_known_slices(dlist_t *disks, dlist_t **known,
77 	dlist_t **bad);
78 static int generate_known_disks(dlist_t **known, dlist_t **bad);
79 static int generate_known_hbas(dlist_t *disks, dlist_t **known);
80 static int generate_known_hba_name(
81 	dm_descriptor_t hba,
82 	dm_descriptor_t	alias,
83 	dm_descriptor_t disk);
84 
85 static void print_known_devices();
86 static void print_device_list(dlist_t *devices);
87 
88 /*
89  * lists of device dm_descriptor_t handles that are usable by layout.
90  * These devices must still pass the user specified available/unavailable
91  * filter before they're actually considered available.
92  *
93  * Lists are populated by discover_usable_devices.
94  */
95 static dlist_t	*_usable_slices = NULL;
96 static dlist_t	*_usable_disks = NULL;
97 static dlist_t	*_usable_hbas = NULL;
98 
99 /*
100  * private flag that remembers if any HBA is known to support MPXIO
101  */
102 static boolean_t _mpxio_enabled = B_FALSE;
103 
104 /*
105  * The slice_class struct is used to group slices by usage class.
106  */
107 typedef struct {
108 	char	*usage;		/* usage description */
109 	dlist_t	*sliceinfo;	/* list with info about each slice with usage */
110 } slice_class_t;
111 
112 #define	USE_DISKSET	"diskset"
113 
114 static int check_slice_usage(
115 	char		*dsname,
116 	dm_descriptor_t slice,
117 	dm_descriptor_t disk,
118 	boolean_t	*avail,
119 	dlist_t		**bad,
120 	dlist_t		**classes);
121 
122 static int check_svm_slice_usage(
123 	char		*dsname,
124 	dm_descriptor_t slice,
125 	dm_descriptor_t disk,
126 	boolean_t	*avail,
127 	dlist_t		**classes);
128 
129 static int save_slice_classification(
130 	char		*dsname,
131 	dm_descriptor_t slice,
132 	dm_descriptor_t disk,
133 	char		*usage,
134 	char		*usage_detail,
135 	dlist_t		**classes);
136 
137 static int generate_usable_disks_and_slices_in_local_set(
138 	dlist_t		**classes,
139 	dlist_t		**bad_disks,
140 	dlist_t		**usable_disks,
141 	dlist_t		**usable_slices);
142 
143 static int generate_usable_disks_and_slices_in_named_set(
144 	char		*dsname,
145 	dlist_t		**classes,
146 	dlist_t		**bad_slices,
147 	dlist_t		**usable_disks,
148 	dlist_t		**usable_slices);
149 
150 static int create_usable_slices(
151 	dm_descriptor_t disk,
152 	dlist_t		*used,
153 	dlist_t		*unused,
154 	dlist_t 	**usable);
155 
156 static int add_new_usable(
157 	dm_descriptor_t disk,
158 	uint64_t	stblk,
159 	uint64_t	nblks,
160 	dlist_t		**next_unused,
161 	dlist_t		**usable);
162 
163 static int update_slice_attributes(
164 	dm_descriptor_t slice,
165 	uint64_t	stblk,
166 	uint64_t	nblks,
167 	uint64_t	nbytes);
168 
169 static int generate_usable_hbas(
170 	dlist_t		*disks,
171 	dlist_t		**usable);
172 
173 static void print_usable_devices();
174 
175 static void print_unusable_devices(
176 	dlist_t		*badslices,
177 	dlist_t		*baddisks,
178 	dlist_t		*usedslices);
179 
180 static char *get_slice_usage_msg(
181 	char		*usage);
182 
183 /*
184  * virtual slices...
185  */
186 static int generate_virtual_slices(
187 	dlist_t 	*avail_disks_local_set,
188 	dlist_t		**usable);
189 
190 /*
191  * multipathed disks have aliases, as do slices on those disks.
192  * these need to be tracked since the user may specify them.
193  * A multi-pathed disk is one connected to the system thru
194  * more than one physical HBA, each connection gets a distinct
195  * name in the device tree and they're all more or less equivalent.
196  * No indication as to how many possible physical connections a
197  * disk may have, so we pick an arbitrary number of aliases to
198  * support. There is nothing significant about this number,
199  * it just controls the number of alias slots that get allocated.
200  */
201 #define	MAX_ALIASES	8
202 
203 /*
204  * attribute name for layout private information stored in
205  * device nvpair attribute lists.
206  */
207 static char *ATTR_DEVICE_ALIASES = "layout_device_aliases";
208 
209 static int compare_start_blocks(
210 	void *desc1, void *desc2);
211 
212 static int compare_desc_display_names(
213 	void *desc1, void *desc2);
214 
215 /*
216  * FUNCTION:	is_mpxio_enabled()
217  *
218  * RETURNS:	boolean_t - B_TRUE - if MPXIO appears enabled for the system
219  *			    B_FALSE - otherwise
220  *
221  * PURPOSE:	returns the value of _mpxio_enabled which is set to B_TRUE
222  *		during system configuration discovery if any of the knwon
223  *		HBAs advertises itself as a "multiplex" controller.
224  */
225 boolean_t
226 is_mpxio_enabled()
227 {
228 	return (_mpxio_enabled);
229 }
230 
231 /*
232  * FUNCTION:	discover_known_devices()
233  *
234  * SIDEEFFECT:	populates the module private lists of known devices
235  *		(_known_slices, _known_disks, _known_hbas).
236  *
237  *		All known devices will also have had their CTD
238  *		short names inferred and stored.
239  *
240  * RETURNS:	int	- 0 on success
241  *			 !0 otherwise
242  *
243  * PURPOSE:	Load physical devices discovered thru libdiskmgt.
244  */
245 int
246 discover_known_devices()
247 {
248 	int	error = 0;
249 
250 	oprintf(OUTPUT_TERSE,
251 		gettext("\nScanning system physical "
252 			"device configuration...\n"));
253 
254 	/* initialize layout_device_cache */
255 	((error = create_device_caches()) != 0) ||
256 
257 	(error = generate_known_disks(&_known_disks, &_bad_disks)) ||
258 	(error = generate_known_slices(_known_disks, &_known_slices,
259 		&_bad_slices)) ||
260 	(error = generate_known_hbas(_known_disks, &_known_hbas));
261 
262 	if (error == 0) {
263 	    print_known_devices();
264 	}
265 
266 	return (error);
267 }
268 
269 /*
270  * FUNCTION:	release_known_devices()
271  *
272  * RETURNS:	int	- 0 on success
273  *			 !0 otherwise
274  *
275  * PURPOSE:	Unloads all state currently held for known
276  *		physical devices.
277  */
278 int
279 release_known_devices(
280 	char	*diskset)
281 {
282 	/* these lists are module private */
283 	dlist_free_items(_bad_slices, NULL);
284 	dlist_free_items(_bad_disks, NULL);
285 	dlist_free_items(_known_slices, NULL);
286 	dlist_free_items(_known_disks, NULL);
287 	dlist_free_items(_known_hbas, NULL);
288 
289 	_bad_slices = NULL;
290 	_bad_disks = NULL;
291 	_known_slices = NULL;
292 	_known_disks = NULL;
293 	_known_hbas = NULL;
294 
295 	/* clean up state kept in layout_device_cache */
296 	release_device_caches();
297 
298 	return (0);
299 }
300 
301 /*
302  * FUNCTION:	discover_usable_devices(char *diskset)
303  *
304  * INPUT:	diskset	- a char * diskset name.
305  *
306  * SIDEEFFECT:	Traverses the lists of known devices and populates the
307  *		module private lists of usable devices (_usable_slices,
308  *		_usable_disks, _usable_hbas), as well as the module
309  *		private list of used slices.
310  *
311  * RETURNS:	int	- 0 on success
312  *			 !0 otherwise
313  *
314  * PURPOSE:	Process the known devices and determine which of them are
315  *		usable for generating volumes in the specified diskset.
316  *
317  *		The specified diskset's name cannot be NULL or 0 length.
318  */
319 int
320 discover_usable_devices(
321 	char	*diskset)
322 {
323 	int	error = 0;
324 
325 	dlist_t *used_classes = NULL;
326 	dlist_t *iter = NULL;
327 
328 	if (diskset == NULL || diskset[0] == '\0') {
329 	    volume_set_error(
330 		    gettext("a diskset name must be specified in "
331 			    "the request\n"));
332 	    return (-1);
333 	}
334 
335 	oprintf(OUTPUT_TERSE,
336 		gettext("\nDetermining usable physical devices "
337 			"for disk set \"%s\"...\n"),
338 		diskset);
339 
340 	error = generate_usable_disks_and_slices_in_local_set(
341 	    &used_classes, &_bad_slices, &_usable_disks, &_usable_slices);
342 	if (error == 0) {
343 
344 	    error = generate_usable_disks_and_slices_in_named_set(
345 		diskset, &used_classes, &_bad_slices, &_usable_disks,
346 		&_usable_slices);
347 	    if (error == 0) {
348 
349 		error = generate_usable_hbas(_usable_disks, &_usable_hbas);
350 		if (error == 0) {
351 
352 		    print_usable_devices();
353 		    print_unusable_devices(
354 			_bad_slices, _bad_disks, used_classes);
355 		}
356 	    }
357 	}
358 
359 	/*
360 	 * free slice classification usage and lists, items are char*
361 	 * the used_classes structure is only filled in if verbose
362 	 * output was requested.
363 	 */
364 	for (iter = used_classes; iter != NULL; iter = iter->next) {
365 	    slice_class_t *class = (slice_class_t *)iter->obj;
366 	    free(class->usage);
367 	    dlist_free_items(class->sliceinfo, free);
368 	}
369 
370 	dlist_free_items(used_classes, free);
371 	return (error);
372 }
373 
374 /*
375  * FUNCTION:	release_usable_devices()
376  *
377  * RETURNS:	int	- 0 on success
378  *			 !0 otherwise
379  *
380  * PURPOSE:	Unloads all state currently held for usable
381  *		physical devices.
382  */
383 int
384 release_usable_devices()
385 {
386 	/* list items are shared with _known_XXX lists */
387 
388 	dlist_free_items(_usable_slices, NULL);
389 	dlist_free_items(_usable_disks, NULL);
390 	dlist_free_items(_usable_hbas, NULL);
391 
392 	_usable_slices = NULL;
393 	_usable_disks = NULL;
394 	_usable_hbas = NULL;
395 
396 	/* clean up state kept in layout_device_util */
397 	release_virtual_slices();
398 
399 	return (0);
400 }
401 
402 /*
403  * FUNCTION:	get_known_slices(dlist_t **list)
404  *		get_known_disks(dlist_t **list)
405  *		get_known_hbas(dlist_t **list)
406  *
407  * OUTPUT:	list	- a dlist_t pointer to hold the returned list of
408  *			devices.
409  *
410  * RETURNS:	int	- 0 on success
411  *			 !0 otherwise
412  *
413  * PURPOSE:	Public accessors for the module private lists of
414  *		available devices.
415  */
416 int
417 get_known_slices(
418 	dlist_t **list)
419 {
420 	*list = _known_slices;
421 
422 	return (0);
423 }
424 
425 int
426 get_known_disks(
427 	dlist_t **list)
428 {
429 	*list = _known_disks;
430 
431 	return (0);
432 }
433 
434 int
435 get_known_hbas(
436 	dlist_t **list)
437 {
438 	*list = _known_hbas;
439 
440 	return (0);
441 }
442 
443 /* make fully qualified DID device name */
444 static char *
445 make_fully_qualified_did_device_name(
446 	char	*device)
447 {
448 	static char	buf[MAXPATHLEN];
449 
450 	if (device != NULL && strrchr(device, '/') == NULL) {
451 	    (void) snprintf(buf, MAXPATHLEN-1, "%s/%s",
452 		    "/dev/did/dsk", device);
453 	    return (buf);
454 	}
455 
456 	return (device);
457 }
458 
459 /*
460  * FUNCTION:	generate_known_disks(dlist_t **known,
461  *			dlist_t **bad)
462  *
463  * INPUT:	NONE
464  *
465  * OUTPUT:	known	- populated list of known disks
466  *		bad	- populated list of known bad disks
467  *
468  * RETURNS:	int	- 0 on success
469  *			 !0 otherwise
470  *
471  * PURPOSE:	Does the system configuration discovery to determine
472  *		what disks are known to be attached to the system.
473  *
474  *		Determines the CTD name for each disk and saves it.
475  */
476 static int
477 generate_known_disks(
478 	dlist_t	**known,
479 	dlist_t **bad)
480 {
481 	int	i;
482 	int	error = 0;
483 	dm_descriptor_t	*ddp;
484 
485 	ddp = dm_get_descriptors(DM_DRIVE, NULL, &error);
486 	(void) add_descriptors_to_free(ddp);
487 
488 	*known = NULL;
489 
490 	if (error != 0) {
491 	    volume_set_error(
492 		    gettext("Error discovering system hardware configuration,\n"
493 		    "unable to communicate with libdiskmgt or diskmgtd.\n"));
494 	    return (-1);
495 	}
496 
497 	if ((ddp == NULL) || (ddp[0] == NULL)) {
498 	    volume_set_error(gettext("there are no known disks\n"));
499 	    return (-1);
500 	}
501 
502 	/* iterate all returned disks and add them to the known list */
503 	for (i = 0; (ddp[i] != NULL) && (error == 0); i++) {
504 	    dm_descriptor_t disk = (dm_descriptor_t)ddp[i];
505 	    dlist_t *aliases = NULL;
506 	    uint32_t mtype = DM_MT_UNKNOWN;
507 	    uint32_t dtype = DM_DT_UNKNOWN;
508 	    boolean_t bad_disk = B_FALSE;
509 	    boolean_t online = B_TRUE;
510 
511 #if defined(i386)
512 	    /* on X86, disks must have a solaris FDISK partition */
513 	    boolean_t solpart = B_FALSE;
514 #endif	/* defined(i386) */
515 
516 	    if (((error = disk_get_is_online(disk, &online)) == 0 &&
517 		online == B_FALSE) || error == ENODEV) {
518 		/* if the disk is offline, report it as bad */
519 		bad_disk = B_TRUE;
520 		error = 0;
521 	    } else
522 
523 	    if (error == 0 &&
524 		(((error = disk_get_media_type(disk, &mtype)) != 0) ||
525 		((error = disk_get_drive_type(disk, &dtype)) != 0)) &&
526 		error == ENODEV) {
527 		/*
528 		 * if any disk attribute access fails with ENODEV
529 		 * report it as bad
530 		 */
531 		bad_disk = B_TRUE;
532 		error = 0;
533 	    } else {
534 
535 		/*
536 		 * Determine whether disk is fixed by checking its
537 		 * drive type.  If drive type is unknown, check media
538 		 * type.
539 		 */
540 		int isfixed = (dtype == DM_DT_FIXED ||
541 		    (dtype == DM_DT_UNKNOWN && mtype == DM_MT_FIXED));
542 
543 		if (!isfixed) {
544 		    continue;  /* ignore non-fixed disks */
545 		}
546 
547 #if defined(i386)
548 		if (((error = disk_get_has_solaris_partition(disk,
549 		    &solpart)) != 0) || (solpart != B_TRUE)) {
550 
551 		    /* X86 drive has no solaris partition, report as bad */
552 		    oprintf(OUTPUT_DEBUG,
553 			    gettext("%s has no solaris FDISK partition.\n"));
554 
555 		    bad_disk = B_TRUE;
556 		}
557 #endif	/* defined(i386) */
558 
559 	    }
560 
561 	    if (bad_disk) {
562 		/* remember bad disks and continue */
563 		if (dlist_contains(*bad,
564 			    (void *)disk, compare_descriptor_names) != B_TRUE) {
565 		    dlist_t *item = dlist_new_item((void *)disk);
566 		    if (item == NULL) {
567 			error = ENOMEM;
568 		    } else {
569 			*bad = dlist_append(item, *bad, AT_TAIL);
570 		    }
571 		}
572 		continue;
573 	    }
574 
575 	    /* get disk name and multipath aliases */
576 	    if ((error = disk_get_aliases(disk, &aliases)) == 0) {
577 		dlist_t *iter;
578 		boolean_t disk_name_set = B_FALSE;
579 
580 		for (iter = aliases;
581 		    (iter != NULL) && (error == 0);
582 		    iter = iter->next) {
583 
584 		    dm_descriptor_t	ap = (uintptr_t)iter->obj;
585 		    char		*alias;
586 
587 		    if ((error = get_name(ap, &alias)) == 0) {
588 			/* save first alias as display name */
589 			if (disk_name_set != B_TRUE) {
590 			    /* make sure DID disk alias is fully qualified */
591 
592 			    if (is_did_disk_name(alias) == B_TRUE) {
593 				char *qual_name =
594 				    make_fully_qualified_did_device_name(alias);
595 
596 				set_display_name(disk, qual_name);
597 				oprintf(OUTPUT_DEBUG,
598 					gettext("DID disk name: %s\n"),
599 					qual_name);
600 			    } else {
601 				set_display_name(disk, alias);
602 				oprintf(OUTPUT_DEBUG,
603 					gettext("disk name: %s\n"),
604 					alias);
605 			    }
606 			    disk_name_set = B_TRUE;
607 
608 			} else {
609 			    /* save others as aliases */
610 			    set_alias(disk, alias);
611 			    oprintf(OUTPUT_DEBUG,
612 				    gettext("  alias: %s\n"),
613 				    alias);
614 			}
615 		    }
616 		}
617 
618 		dlist_free_items(aliases, NULL);
619 	    }
620 
621 	    if (error == 0) {
622 		dlist_t *item = dlist_new_item((void *)disk);
623 		if (item == NULL) {
624 		    error = ENOMEM;
625 		} else {
626 		    *known =
627 			dlist_insert_ordered(item, *known,
628 				ASCENDING, compare_desc_display_names);
629 		}
630 	    }
631 	}
632 
633 	if (ddp != NULL) {
634 	    free(ddp);
635 	}
636 
637 	return (error);
638 }
639 
640 /*
641  * FUNCTION:	generate_known_slices(dlist_t *disks,
642  *		dlist_t **known, dlist_t **bad)
643  *
644  * OUTPUT:	disks	- a pointer to a list of known disks
645  *		known	- a pointer to a dlist_t list to hold the known slices
646  *		bad	- a pointer to a dlist_t to hold the bad slices
647  *
648  * RETURNS:	int	- 0 on success
649  *			 !0 otherwise.
650  *
651  * PURPOSE:	Examines input list of known disks and determines the slices
652  *		attached to each.
653  *
654  *		Some slices returned from libdiskmgt may not really exist,
655  *		this is detected when trying to get more information about
656  *		the slice -- ENODEV is returned.  Any such slices will be
657  *		added to the bad slice list.
658  */
659 static int
660 generate_known_slices(
661 	dlist_t		*disks,
662 	dlist_t		**known,
663 	dlist_t		**bad)
664 {
665 	dlist_t		*iter;
666 	int		error = 0;
667 
668 	/* iterate list of disks and add their slices to the known list */
669 	for (iter = disks; (iter != NULL) && (error == 0); iter = iter->next) {
670 
671 	    dm_descriptor_t disk = (uintptr_t)iter->obj;
672 	    dlist_t *slices = NULL;
673 	    dlist_t *iter1;
674 	    char *dname = NULL;
675 	    boolean_t disk_ctd_alias_derived = B_FALSE;
676 
677 	    if (((error = disk_get_slices(disk, &slices)) != 0) ||
678 		((error = get_display_name(disk, &dname)) != 0)) {
679 		continue;
680 	    }
681 
682 	    for (iter1 = slices;
683 		(iter1 != NULL) && (error == 0);
684 		iter1 = iter1->next) {
685 
686 		dm_descriptor_t slice = (uintptr_t)iter1->obj;
687 		uint32_t index = 0;
688 		nvlist_t *attrs = NULL;
689 		char *sname = NULL;
690 
691 		if (((error = get_name(slice, &sname)) != 0) ||
692 		    ((error = slice_get_index(slice, &index)) != 0) ||
693 		    ((error = get_cached_attributes(slice, &attrs)) != 0)) {
694 
695 		    if (error == ENODEV) {
696 			/* bad slice, remember it and continue */
697 			dlist_t *item = dlist_new_item((void *)slice);
698 			if (item == NULL) {
699 			    error = ENOMEM;
700 			} else {
701 			    *bad = dlist_insert_ordered(
702 				    item, *bad,
703 				    ASCENDING, compare_descriptor_names);
704 			    error = 0;
705 			}
706 		    }
707 		    continue;
708 		}
709 
710 		if ((error == 0) && (is_did_slice_name(sname) == B_TRUE) &&
711 		    (disk_ctd_alias_derived == B_FALSE)) {
712 		    /* BEGIN CSTYLED */
713 		    /*
714 		     * If the slice name is a DID name, get the local CTD
715 		     * name for slice, extract the disk name and add it as
716 		     * an alias for the disk.
717 		     *
718 		     * This is the only way to derive the CTD alias for the
719 		     * disk when DID is enabled.
720 		     *
721 		     * The disk_ctd_alias_derived flag ensure the disk's
722 		     * CTD alias is only set once.
723 		     *
724 		     * The slice's CTD aliases are then derived from the
725 		     * disk's CTD alias in the normal, non-DID name processing
726 		     * which happens below.
727 		     */
728 		    /* END CSTYLED */
729 		    char *local = NULL;
730 		    if ((error = nvlist_lookup_string(attrs, DM_LOCALNAME,
731 				&local)) != 0) {
732 			if (error == ENOENT) {
733 			    /* no local name -> no DID */
734 			    error = 0;
735 			}
736 		    } else {
737 			char *localdisk = NULL;
738 			char *diskonly = NULL;
739 			if ((error = extract_diskname(local,
740 			    &localdisk)) == 0) {
741 			    if ((diskonly = strrchr(localdisk, '/')) != NULL) {
742 				++diskonly;
743 			    } else {
744 				diskonly = localdisk;
745 			    }
746 			    oprintf(OUTPUT_DEBUG,
747 				    gettext("  set DID disk CTD alias: %s\n"),
748 				    diskonly);
749 			    error = set_alias(disk, diskonly);
750 			    free(localdisk);
751 			    disk_ctd_alias_derived = B_TRUE;
752 			}
753 		    }
754 		}
755 
756 		/* derive slice display name from disk's display name */
757 		if (error == 0) {
758 		    if ((error = make_slicename_for_diskname_and_index(
759 			dname, index, &sname)) == 0) {
760 			error = set_display_name(slice, sname);
761 		    }
762 		}
763 
764 		/* set slice aliases using disk aliases */
765 		if (error == 0) {
766 		    dlist_t *aliases = NULL;
767 		    if ((error = get_aliases(disk, &aliases)) == 0) {
768 
769 			dlist_t *iter2 = aliases;
770 			for (; (iter2 != NULL) && (error == 0);
771 			    iter2 = iter2->next) {
772 
773 			    char *dalias = (char *)iter2->obj;
774 			    char *salias = NULL;
775 
776 			    if ((error = make_slicename_for_diskname_and_index(
777 				dalias, index, &salias)) == 0) {
778 				error = set_alias(slice, salias);
779 				free(salias);
780 			    }
781 			}
782 			dlist_free_items(aliases, free);
783 		    }
784 		}
785 
786 		if (error == 0) {
787 		    dlist_t *item = dlist_new_item((void *)slice);
788 		    if (item == NULL) {
789 			error = ENOMEM;
790 		    } else {
791 			*known =
792 			    dlist_insert_ordered(
793 				    item, *known,
794 				    ASCENDING, compare_desc_display_names);
795 		    }
796 		}
797 	    }
798 
799 	    dlist_free_items(slices, NULL);
800 	}
801 
802 	return (error);
803 }
804 
805 /*
806  * FUNCTION:	generate_known_hbas(dlist_t *disks, dlist_t **known)
807  *
808  * INPUT:	diskset	- a char * diskset name.
809  *
810  * OUTPUT:	populates the list of known HBAs.
811  *
812  * RETURNS:	int	- 0 on success
813  *			 !0 otherwise
814  *
815  * PURPOSE:	Examines known disk list and derives the list of known HBAs.
816  *
817  *		Determines the CTD name for an HBA and saves it.
818  */
819 static int
820 generate_known_hbas(
821 	dlist_t	*disks,
822 	dlist_t	**known)
823 {
824 	dlist_t	*iter;
825 	int	error = 0;
826 
827 	/*
828 	 * for each known disk follow its HBA connections and
829 	 * assemble the list of known HBAs.
830 	 */
831 	for (iter = disks;
832 	    (iter != NULL) && (error == 0);
833 	    iter = iter->next) {
834 
835 	    dm_descriptor_t	disk = (uintptr_t)iter->obj;
836 	    dlist_t 		*hbas = NULL;
837 	    dlist_t 		*iter2 = NULL;
838 	    dlist_t		*iter3 = NULL;
839 	    dlist_t		*aliases = NULL;
840 	    char		*dname = NULL;
841 
842 	    ((error = get_display_name(disk, &dname)) != 0) ||
843 	    (error = disk_get_aliases(disk, &aliases)) ||
844 	    (error = disk_get_hbas(disk, &hbas));
845 
846 	    if (error == 0) {
847 
848 		if ((hbas == NULL) || (dlist_length(hbas) == 0)) {
849 
850 		    oprintf(OUTPUT_DEBUG,
851 			    gettext("Disk %s has no HBA/Controller?!\n"),
852 			    dname);
853 		    error = -1;
854 
855 		    dlist_free_items(hbas, NULL);
856 		    dlist_free_items(aliases, NULL);
857 
858 		    continue;
859 		}
860 
861 		for (iter2 = hbas, iter3 = aliases;
862 		    iter2 != NULL && iter3 != NULL;
863 		    iter2 = iter2->next, iter3 = iter3->next) {
864 
865 		    dm_descriptor_t	hba = (uintptr_t)iter2->obj;
866 		    dm_descriptor_t	alias = (uintptr_t)iter3->obj;
867 		    dlist_t		*item = NULL;
868 
869 		    /* scan list of known HBAs and see if known */
870 		    if (dlist_contains(*known,
871 			(void*)hba, compare_descriptor_names) == B_TRUE) {
872 			/* known HBA */
873 			continue;
874 		    }
875 
876 		    /* see if HBA supports MPXIO */
877 		    if ((error == 0) && (_mpxio_enabled != B_TRUE)) {
878 			hba_is_multiplex(hba, &_mpxio_enabled);
879 		    }
880 
881 		    /* generate a CTD name for HBA */
882 		    error = generate_known_hba_name(hba, alias, disk);
883 		    if (error == 0) {
884 			/* add to known HBA list */
885 			if ((item = dlist_new_item((void *)hba)) == NULL) {
886 			    error = ENOMEM;
887 			} else {
888 			    *known =
889 				dlist_insert_ordered(item, *known,
890 				    ASCENDING, compare_desc_display_names);
891 			}
892 		    }
893 		}
894 	    }
895 
896 	    dlist_free_items(aliases, NULL);
897 	    dlist_free_items(hbas, NULL);
898 	}
899 
900 	return (error);
901 }
902 
903 /*
904  * FUNCTION:	generate_known_hba_name(dm_descriptor_t hba,
905  *		dm_descriptor_t alias, char *diskname)
906  *
907  * INPUT:	hba	- a dm_descriptor_t HBA handle.
908  *		alias	- a dm_descriptor_t disk alias handle.
909  *		diskname - a char * disk name
910  *
911  * RETURNS:	int	- 0 on success
912  *			 !0 otherwise
913  *
914  * PURPOSE:	Sets the CTD name for the input HBA.
915  *
916  *		The CTD name for the HBA is generated from the input
917  *		disk alias (ex: cXdXtXsX) or from the disk name if
918  *		the input alias is a DID name (ex: dX).
919  */
920 static int
921 generate_known_hba_name(
922 	dm_descriptor_t	hba,
923 	dm_descriptor_t	alias,
924 	dm_descriptor_t disk)
925 {
926 	char	*hbaname = NULL;
927 	char	*aliasname = NULL;
928 	int	error = 0;
929 
930 	((error = get_name(alias, &aliasname)) != 0) ||
931 	(error = extract_hbaname(aliasname, &hbaname));
932 	if (error != 0) {
933 	    free(hbaname);
934 	    return (error);
935 	}
936 
937 	/* see if the input alias is a DID name... */
938 	if (is_did_disk_name(aliasname) == B_TRUE) {
939 
940 	    /* look for a non-DID name in disk's aliases */
941 	    dlist_t *aliases = NULL;
942 	    error = get_aliases(disk, &aliases);
943 
944 	    for (; (error == 0) && (aliases != NULL);
945 		aliases = aliases->next) {
946 
947 		aliasname = (char *)aliases->obj;
948 		if (is_did_disk_name(aliasname) != B_TRUE) {
949 		    /* this is the "local" CTD name generated by */
950 		    /* generate_known_disks() above */
951 		    error = extract_hbaname(aliasname, &hbaname);
952 		    if ((error == 0) && (hbaname != NULL)) {
953 			set_display_name(hba, hbaname);
954 			break;
955 		    }
956 		}
957 	    }
958 	    dlist_free_items(aliases, free);
959 
960 	} else {
961 	    /* use whatever was derived from the alias name */
962 	    set_display_name(hba, hbaname);
963 	}
964 
965 	return (error);
966 }
967 
968 /*
969  * FUNCTION:	print_known_devices()
970  *
971  * PURPOSE:	Print out the known devices.
972  *
973  *		Iterates the lists of known slices, disks and HBAs
974  *		and prints out their CTD and device names.
975  */
976 static void
977 print_known_devices(
978 	char	*diskset)
979 {
980 	int i = 0;
981 	struct {
982 		char *msg;
983 		dlist_t *list;
984 	}	devs[3];
985 
986 	devs[0].msg = gettext("HBA/Controllers");
987 	devs[0].list = _known_hbas;
988 	devs[1].msg = gettext("disks");
989 	devs[1].list = _known_disks;
990 	devs[2].msg = gettext("slices");
991 	devs[2].list = _known_slices;
992 
993 	for (i = 0; i < 3; i++) {
994 
995 	    oprintf(OUTPUT_VERBOSE,
996 		    gettext("\n  These %s are known:\n\n"),
997 		    devs[i].msg);
998 
999 	    print_device_list(devs[i].list);
1000 	}
1001 }
1002 
1003 /*
1004  * FUNCTION:	get_usable_slices(dlist_t **list)
1005  *
1006  * OUTPUT:	list	- a dlist_t pointer to hold the returned list of
1007  *			devices.
1008  *
1009  * RETURNS:	int	- 0 on success
1010  *			 !0 otherwise
1011  *
1012  * PURPOSE:	Public accessors the the modules private lists of
1013  *		available devices.
1014  *
1015  *		The functions are keyed by diskset name in the event
1016  *		objects in different disksets are loaded concurrently.
1017  */
1018 int
1019 get_usable_slices(
1020 	dlist_t **list)
1021 {
1022 	*list = _usable_slices;
1023 
1024 	return (0);
1025 }
1026 
1027 int
1028 get_usable_disks(
1029 	dlist_t **list)
1030 {
1031 	*list = _usable_disks;
1032 
1033 	return (0);
1034 }
1035 
1036 int
1037 get_usable_hbas(
1038 	dlist_t **list)
1039 {
1040 	*list = _usable_hbas;
1041 
1042 	return (0);
1043 }
1044 
1045 /*
1046  * FUNCTION:	generate_usable_disks_and_slices_in_local_set(dlist_t **classes,
1047  *			dlist_t **bad_disks, dlist_t **usable_disks,
1048  *			dlist_t **usable_slices)
1049  *
1050  * OUTPUT:	used_classes - a pointer to a list of slice_class_t structs
1051  *			updated with known slices that have detected uses
1052  *			added to the correct class'e list of slices.
1053  *		bad_disks - a pointer to a list of bad/unusable disks updated
1054  *			with any bad disks that were detected
1055  *		useable_disks - a pointer to a list of usable disks
1056  *		useable_slices - a pointer to a list of usable slices
1057  *
1058  * RETURNS:	int	- 0 on success
1059  *			 !0 otherwise.
1060  *
1061  * PURPOSE:	Scans the disks in the local set to determine which are
1062  *		usable during layout processing.
1063  *
1064  *		Determines which are usable by layout using usages detected
1065  *		by libdiskmgt.
1066  */
1067 static int
1068 generate_usable_disks_and_slices_in_local_set(
1069 	dlist_t **classes,
1070 	dlist_t **bad_slices,
1071 	dlist_t **usable_disks,
1072 	dlist_t **usable_slices)
1073 {
1074 	char	*dsname = MD_LOCAL_NAME;
1075 	dlist_t *disks;
1076 	dlist_t *iter;
1077 	int 	error;
1078 
1079 	/* Get disks in local set */
1080 	error = get_disks_in_diskset(dsname, &disks);
1081 	if (error != 0) {
1082 	    return (error);
1083 	}
1084 
1085 	/* For each disk in this set... */
1086 	for (iter = disks; iter != NULL && error == 0; iter = iter->next) {
1087 	    dm_descriptor_t disk = (uintptr_t)iter->obj;
1088 	    dlist_t *slices;
1089 
1090 	    /* Get slices on this disk */
1091 	    error = disk_get_slices(disk, &slices);
1092 	    if (error == 0) {
1093 		dlist_t *iter2;
1094 
1095 		/*
1096 		 * Assume disk is available until a bad or unavailable
1097 		 * slice is found
1098 		 */
1099 		boolean_t avail = B_TRUE;
1100 		boolean_t bad_disk = B_FALSE;
1101 
1102 		/* For each slice on this disk... */
1103 		for (iter2 = slices;
1104 		    iter2 != NULL && error == 0 &&
1105 			avail == B_TRUE && bad_disk == B_FALSE;
1106 		    iter2 = iter2->next) {
1107 
1108 		    dm_descriptor_t slice = (uintptr_t)iter2->obj;
1109 		    dlist_t *bad_slices_on_this_disk = NULL;
1110 
1111 		    /* Is this slice available? */
1112 		    error = check_slice_usage(dsname, slice,
1113 			disk, &avail, &bad_slices_on_this_disk, classes);
1114 
1115 		    /* Is the slice bad (inaccessible)? */
1116 		    if (error != 0 && bad_slices_on_this_disk != NULL) {
1117 			bad_disk = B_TRUE;
1118 			*bad_slices = dlist_append_list(
1119 			    *bad_slices, bad_slices_on_this_disk);
1120 		    }
1121 		}
1122 
1123 		/* Is the disk available? */
1124 		if (error == 0 && bad_disk == B_FALSE && avail == B_TRUE) {
1125 		    error = dlist_append_object(
1126 			(void *)disk, usable_disks, AT_TAIL);
1127 		}
1128 
1129 		dlist_free_items(slices, NULL);
1130 	    }
1131 	}
1132 
1133 	dlist_free_items(disks, NULL);
1134 
1135 	if (error == 0) {
1136 	    /* BEGIN CSTYLED */
1137 	    /*
1138 	     * Now reslice usable disks in the local set to
1139 	     * simulate the slices they'll have when they're added
1140 	     * to the named disk set, and add these resulting
1141 	     * virtual slices to the list of available slices.
1142 	     */
1143 	    /* END CSTYLED */
1144 	    error = generate_virtual_slices(*usable_disks, usable_slices);
1145 	}
1146 
1147 	return (error);
1148 }
1149 
1150 /*
1151  * FUNCTION:	generate_virtual_slices(dlist_t *unused, dlist_t **usable)
1152  *
1153  * INPUT:	slice_classes - a list of unused slice dm_descriptor_t handles.
1154  *
1155  * OUTPUT:	usable - pointer to the list of usable slices, updated
1156  *			with any created virtual slices.
1157  *
1158  * RETURNS:	int	- 0 on success
1159  *			 !0 otherwise.
1160  *
1161  * PURPOSE:	Helper which creates virtual slices for each disk which
1162  *		could be added to a diskset if necessary...
1163  *
1164  *		Search the input list of slice classes for the entry
1165  *		containing slices known to be available for use by layout.
1166  *
1167  *		Iterate the list of unused slices and determine the set
1168  *		of unique disks.
1169  *
1170  *		For each unique disk, create virtual slice descriptors to
1171  *		represent those that will exist if/when the disk is added
1172  *		to the diskset.
1173  *
1174  *		Add theese virtual slices to the list of usable slices.
1175  */
1176 static int
1177 generate_virtual_slices(
1178 	dlist_t 	*avail_disks_local_set,
1179 	dlist_t		**usable)
1180 {
1181 	dlist_t	*iter = NULL;
1182 	int	error = 0;
1183 
1184 	/* generate virtual slices */
1185 	error = create_virtual_slices(avail_disks_local_set);
1186 	if (error == 0) {
1187 
1188 	    get_virtual_slices(&iter);
1189 	    for (; (iter != NULL) && (error == 0); iter = iter->next) {
1190 
1191 		dlist_t *item = dlist_new_item((void *) iter->obj);
1192 		if (item == NULL) {
1193 		    error = ENOMEM;
1194 		} else {
1195 		    *usable =
1196 			dlist_insert_ordered(item, *usable,
1197 				ASCENDING, compare_desc_display_names);
1198 		}
1199 	    }
1200 	}
1201 
1202 	return (error);
1203 }
1204 
1205 /*
1206  * FUNCTION:	generate_usable_disks_and_slices_in_named_set(char *dsname,
1207  *			dlist_t **classes, dlist_t **bad_slices,
1208  *			dlist_t **usable_slices, dlist_t **usable_disks)
1209  *
1210  * INPUT:	dsname	- a char * diskset name.
1211  *
1212  * OUTPUT:	classes	- pointer to a list of slice_class_t structs,
1213  *			updated to include slices in the disk set with
1214  *			known uses.
1215  * 		bad_slices - pointer to a list of bad/unusable slices,
1216  *			updated to include slices in the disk set that
1217  *			are inaccessible or no longer existent.
1218  *		usable_slices - pointer to a list of usable slices in the
1219  *			disk set.
1220  *		usable_disks - pointer to a list of usable disks in the
1221  *			disk set.
1222  *
1223  * RETURNS:	int	- 0 on success
1224  *			 !0 otherwise.
1225  *
1226  * PURPOSE:	1. determine the disks in the named disk set
1227  *		2. determine the used slices on the disks
1228  *		3. determine the unused slices on the disks
1229  *		4. look for unused space on the disks and collect it
1230  *		   into an existing unused slice, or create a new
1231  *		   virtual slice.
1232  */
1233 static int
1234 generate_usable_disks_and_slices_in_named_set(
1235 	char		*dsname,
1236 	dlist_t		**classes,
1237 	dlist_t		**bad_slices,
1238 	dlist_t		**usable_disks,
1239 	dlist_t		**usable_slices)
1240 {
1241 	dlist_t		*disks = NULL;
1242 	dlist_t		*iter = NULL;
1243 	int		error = 0;
1244 
1245 	error = get_disks_in_diskset(dsname, &disks);
1246 	if (error != 0) {
1247 	    return (error);
1248 	}
1249 
1250 	/* For each disk... */
1251 	for (iter = disks;
1252 	    iter != NULL && error == 0;
1253 	    iter = iter->next) {
1254 
1255 	    dm_descriptor_t	disk = (uintptr_t)iter->obj;
1256 	    dlist_t		*iter2;
1257 	    dlist_t		*slices = NULL;
1258 	    dlist_t		*bad_slices_on_this_disk = NULL;
1259 	    dlist_t		*used_slices_on_this_disk = NULL;
1260 	    dlist_t		*unused_slices_on_this_disk = NULL;
1261 	    boolean_t		bad_disk = B_FALSE;
1262 
1263 	    error = disk_get_slices(disk, &slices);
1264 	    if (error != 0) {
1265 		break;
1266 	    }
1267 
1268 	    /* Determine the used, unused, and bad slices on the disk */
1269 
1270 	    /* For each slice... */
1271 	    for (iter2 = slices;
1272 		iter2 != NULL && error == 0 && bad_disk == B_FALSE;
1273 		iter2 = iter2->next) {
1274 
1275 		dm_descriptor_t slice = (uintptr_t)iter2->obj;
1276 
1277 		boolean_t	rsvd = B_FALSE;
1278 		boolean_t	avail = B_FALSE;
1279 
1280 		/* Get slice usage */
1281 		if (((error = is_reserved_slice(slice, &rsvd)) == 0) &&
1282 		    ((error = check_slice_usage(dsname, slice, disk, &avail,
1283 			&bad_slices_on_this_disk, classes)) == 0)) {
1284 
1285 		    /* Is the slice bad (inaccessible)? */
1286 		    if (bad_slices_on_this_disk != NULL) {
1287 			*bad_slices = dlist_append_list(
1288 			    *bad_slices, bad_slices_on_this_disk);
1289 			/*
1290 			 * Since one slice on this disk is bad, don't
1291 			 * use any slices on this disk
1292 			 */
1293 			bad_disk = B_TRUE;
1294 		    } else {
1295 
1296 			dlist_t *item = dlist_new_item((void *)slice);
1297 			if (item == NULL) {
1298 			    error = ENOMEM;
1299 			} else {
1300 			    /* Add slice to used/unused list as appropriate */
1301 			    if (avail == B_TRUE && rsvd == B_FALSE) {
1302 				unused_slices_on_this_disk = dlist_append(
1303 				    item, unused_slices_on_this_disk, AT_TAIL);
1304 			    } else {
1305 				used_slices_on_this_disk =
1306 				    dlist_insert_ordered(item,
1307 					used_slices_on_this_disk,
1308 					ASCENDING, compare_start_blocks);
1309 			    }
1310 			}
1311 		    }
1312 		}
1313 	    }
1314 
1315 	    /* Done iterating slices */
1316 
1317 	    if (error == 0 && bad_disk == B_FALSE) {
1318 		/* For each unused slice... */
1319 		for (iter2 = unused_slices_on_this_disk;
1320 		    iter2 != NULL && error == 0;
1321 		    iter2 = iter2->next) {
1322 
1323 		    dm_descriptor_t slice = (uintptr_t)iter2->obj;
1324 		    error = update_slice_attributes(slice, 0, 0, 0);
1325 
1326 		    /* Only do this once */
1327 		    if (error == 0 && iter2 == unused_slices_on_this_disk) {
1328 			error = add_modified_disk(NULL, disk);
1329 		    }
1330 		}
1331 
1332 		if (error == 0) {
1333 		    /* Create usable slices from the used/unused slice lists */
1334 		    error = create_usable_slices(disk, used_slices_on_this_disk,
1335 			unused_slices_on_this_disk, usable_slices);
1336 		    if (error == 0) {
1337 			error = dlist_append_object(
1338 			    (void *)disk, usable_disks, AT_TAIL);
1339 		    }
1340 		}
1341 	    }
1342 
1343 	    dlist_free_items(slices, NULL);
1344 	    dlist_free_items(used_slices_on_this_disk, NULL);
1345 	    dlist_free_items(unused_slices_on_this_disk, NULL);
1346 	}
1347 
1348 	return (error);
1349 }
1350 
1351 /*
1352  * FUNCTION:	create_usable_slices(dm_descriptor_t disk, dlist_t *used,
1353  *			dlist_t *unused, dlist_t **usable);
1354  *
1355  * INPUT:	disk	- a dm_descriptor_t disk handle
1356  *		used	- pointer to a list of pvt_t structs
1357  *			  representing existing used slices
1358  *			  on the input disk.
1359  *		unused	- pointer to a list of pvt_t structs
1360  *			  representing existing unused slices
1361  *			  on the input disk.
1362  *
1363  * OUTPUT:	usable	- pointer to a list of pvts representing slices
1364  *			which can be used for new volume layouts.
1365  *
1366  *			Slices in this list have any available space on the
1367  *			disk collected into the fewest, lowest indexed slices
1368  *			possible.
1369  *
1370  * RETURNS:	int	- 0 on success
1371  *			 !0 otherwise.
1372  *
1373  * PURPOSE:	helper for generate_usable_slices_and_disks_in_diskset() which
1374  *		turns any detected free space on the input disk into one or
1375  *		more slices.
1376  */
1377 static int
1378 create_usable_slices(
1379 	dm_descriptor_t disk,
1380 	dlist_t		*used,
1381 	dlist_t		*unused,
1382 	dlist_t		**usable)
1383 {
1384 	dlist_t		*iter;
1385 	int		error = 0;
1386 	boolean_t	first = B_TRUE;
1387 	dlist_t		*next_unused = unused;
1388 
1389 	char		*dname = NULL;
1390 	uint64_t 	disk_firstblk = 0;
1391 	uint64_t 	disk_nblks = 0;
1392 	uint64_t 	disk_endblk = 0;
1393 
1394 	oprintf(OUTPUT_DEBUG,
1395 		gettext("\n  create_usable_slices for disk\n"));
1396 
1397 	/* get necessary info about disk: */
1398 	error = get_display_name(disk, &dname);
1399 	if (error != 0) {
1400 	    return (error);
1401 	}
1402 
1403 	/* disk start block is first usable block */
1404 	error = disk_get_start_block(disk, &disk_firstblk);
1405 	if (error != 0) {
1406 	    return (error);
1407 	}
1408 
1409 	/* disk size determines last usable disk block */
1410 	error = disk_get_size_in_blocks(disk, &disk_nblks);
1411 	if (error != 0) {
1412 	    return (error);
1413 	}
1414 
1415 	disk_endblk = disk_firstblk + disk_nblks - 1;
1416 
1417 	/* search for gaps before, between and after used slices */
1418 	for (iter = used; iter != NULL && error == 0; iter = iter->next) {
1419 
1420 	    dm_descriptor_t cur = (uintptr_t)iter->obj;
1421 
1422 	    uint64_t cur_stblk = 0;
1423 	    uint64_t cur_nblks = 0;
1424 	    uint64_t cur_endblk = 0;
1425 	    uint32_t cur_index = 0;
1426 
1427 	    uint64_t new_stblk = 0;
1428 	    uint64_t new_endblk = 0;
1429 
1430 	    char *sname = NULL;
1431 	    (void) get_display_name(cur, &sname);
1432 
1433 	    if (((error = slice_get_index(cur, &cur_index)) != 0) ||
1434 		((error = slice_get_start_block(cur, &cur_stblk)) != 0) ||
1435 		((error = slice_get_size_in_blocks(cur, &cur_nblks)) != 0)) {
1436 		continue;
1437 	    }
1438 
1439 	    cur_endblk = cur_stblk + cur_nblks - 1;
1440 
1441 	    oprintf(OUTPUT_DEBUG,
1442 		    gettext("  used slice %d (%10llu to %10llu)\n"),
1443 		    cur_index, cur_stblk, cur_endblk);
1444 
1445 	    if (first == B_TRUE) {
1446 		/* first slice: make sure it starts at disk_firstblk */
1447 		first = B_FALSE;
1448 		if (cur_stblk != disk_firstblk) {
1449 		    /* close gap at beginning of disk */
1450 		    new_stblk = disk_firstblk;
1451 		    new_endblk = cur_stblk - 1;
1452 
1453 		    oprintf(OUTPUT_DEBUG,
1454 			    gettext("    unused space before first "
1455 				    "used slice\n"));
1456 		}
1457 	    }
1458 
1459 	    if (iter->next != NULL) {
1460 		/* check for gap between slices */
1461 		dm_descriptor_t next = (uintptr_t)iter->next->obj;
1462 		uint64_t next_stblk = 0;
1463 		uint32_t next_index = 0;
1464 
1465 		if (((error = slice_get_start_block(next, &next_stblk)) == 0) &&
1466 		    ((error = slice_get_index(next, &next_index)) == 0)) {
1467 		    if (cur_endblk != next_stblk - 1) {
1468 			/* close gap between slices */
1469 			new_stblk = cur_endblk + 1;
1470 			new_endblk = next_stblk - 1;
1471 
1472 			oprintf(OUTPUT_DEBUG,
1473 				gettext("    unused space between slices "
1474 					"%d and %d\n"), cur_index, next_index);
1475 		    }
1476 		}
1477 
1478 	    } else {
1479 		/* last slice: make sure it includes last block on disk */
1480 		if (cur_endblk != disk_endblk) {
1481 		    /* close gap at end of disk */
1482 		    new_stblk = cur_endblk + 1;
1483 		    new_endblk = disk_endblk;
1484 
1485 		    oprintf(OUTPUT_DEBUG,
1486 			    gettext("    unused space after last slice "
1487 				    "cur_endblk: %llu disk_endblk: %llu\n"),
1488 			    cur_endblk, disk_endblk);
1489 		}
1490 	    }
1491 
1492 	    if ((error == 0) && (new_endblk != 0)) {
1493 		error = add_new_usable(disk, new_stblk,
1494 			new_endblk - new_stblk + 1, &next_unused, usable);
1495 	    }
1496 	}
1497 
1498 	if (error != 0) {
1499 	    dlist_free_items(*usable, free);
1500 	    *usable = NULL;
1501 	}
1502 
1503 	return (error);
1504 }
1505 
1506 /*
1507  * FUNCTION:	add_new_usable(dm_descriptor_t disk, uint64_t stblk,
1508  *			uint64_t nblks, dlist_t **next_unused,
1509  *			dlist_t **usable);
1510  *
1511  * INPUT:	disk	- a dm_descriptor_t disk handle
1512  *		stblk	- start block of the usable space
1513  *		nblks	- number of usable blocks
1514  *		next_unused	- pointer to the next unused slice
1515  *
1516  * OUTPUT:	next_unused	- updated pointer to the next unused slice
1517  *		usable	- possibly updated pointer to a list of slices on
1518  *			the disk with usable space
1519  *
1520  * RETURNS:	int	- 0 on success
1521  *			 !0 otherwise.
1522  *
1523  * PURPOSE:	helper for create_usable_slices() which turns free space
1524  *		on the input disk into a usable slice.
1525  *
1526  *		If possible an existing unused slice will be recycled
1527  *		into a usable slice. If there are none, a new virtual
1528  *		slice will be created.
1529  */
1530 static int
1531 add_new_usable(
1532 	dm_descriptor_t disk,
1533 	uint64_t	stblk,
1534 	uint64_t	nblks,
1535 	dlist_t		**next_unused,
1536 	dlist_t		**usable)
1537 {
1538 	dm_descriptor_t new_usable = 0;
1539 	int		error = 0;
1540 
1541 	/* try to use an existing unused slice for the usable slice */
1542 	if (*next_unused != NULL) {
1543 	    new_usable = (uintptr_t)((*next_unused)->obj);
1544 	    *next_unused = (*next_unused)->next;
1545 
1546 	    oprintf(OUTPUT_DEBUG,
1547 		    gettext("\trecyling used slice into usable slice "
1548 			    "start: %llu, end: %llu\n"),
1549 		    stblk, stblk + nblks + 1);
1550 	}
1551 
1552 	if (new_usable == NULL) {
1553 	    /* no unused slices, try to make a new virtual slice */
1554 	    uint32_t index = UINT32_MAX;
1555 	    error = disk_get_available_slice_index(disk, &index);
1556 	    if ((error == 0) && (index != UINT32_MAX)) {
1557 
1558 		char *dname = NULL;
1559 		error = get_display_name(disk, &dname);
1560 		if (error == 0) {
1561 
1562 		    char buf[MAXNAMELEN];
1563 		    (void) snprintf(buf, MAXNAMELEN-1, "%ss%d", dname, index);
1564 		    error = add_virtual_slice(buf, index, 0, 0, disk);
1565 		    if (error == 0) {
1566 			/* retrieve the virtual slice */
1567 			error = slice_get_by_name(buf, &new_usable);
1568 		    }
1569 		}
1570 	    }
1571 	}
1572 
1573 	if ((error == 0) && (new_usable != (dm_descriptor_t)0)) {
1574 	    /* BEGIN CSTYLED */
1575 	    /*
1576 	     * have an unused slice, update its attributes to reflect
1577 	     * the usable space it represents
1578 	     */
1579 	    /* END CSTYLED */
1580 	    uint64_t disk_blksz = 0;
1581 	    error = disk_get_blocksize(disk, &disk_blksz);
1582 	    if (error == 0) {
1583 		error = update_slice_attributes(new_usable, stblk,
1584 		    nblks, nblks * disk_blksz);
1585 		if (error == 0) {
1586 		    error = dlist_append_object(
1587 			(void *)new_usable, usable, AT_TAIL);
1588 		}
1589 	    }
1590 	}
1591 
1592 	return (error);
1593 }
1594 
1595 /*
1596  * FUNCTION:	update_slice_attributes(dm_descriptor_t slice, uint64_t stblk,
1597  *			uint64_t nblks, uint64_t nbytes)
1598  *
1599  * INPUT:	slice	- a dm_descriptor_t slice handle
1600  *		stblk	- start block of the usable space
1601  *		nblks	- size of slice in blocks
1602  *		nbytes	- size of slice in bytes
1603  *
1604  * SIDEEFFECT:	adds a modification record for the slice.
1605  *
1606  * RETURNS:	int	- 0 on success
1607  *			 !0 otherwise.
1608  *
1609  * PURPOSE:	utility which updates several slice attributes in one call.
1610  */
1611 static int
1612 update_slice_attributes(
1613 	dm_descriptor_t slice,
1614 	uint64_t	stblk,
1615 	uint64_t	nblks,
1616 	uint64_t	nbytes)
1617 {
1618 	char		*sname = NULL;
1619 	uint32_t	 index = 0;
1620 	int		error = 0;
1621 
1622 	if ((error = get_display_name(slice, &sname)) == 0) {
1623 	    if ((error = slice_get_index(slice, &index)) == 0) {
1624 		if ((error = slice_set_start_block(slice, stblk)) == 0) {
1625 		    if ((error = slice_set_size_in_blocks(slice, nblks)) == 0) {
1626 			if (nblks == 0) {
1627 			    error = add_slice_to_remove(sname, index);
1628 			} else {
1629 			    error = assemble_modified_slice((dm_descriptor_t)0,
1630 				    sname, index, stblk, nblks, nbytes, NULL);
1631 			}
1632 		    }
1633 		}
1634 	    }
1635 	}
1636 
1637 	return (error);
1638 }
1639 
1640 /*
1641  * FUNCTION:	generate_usable_hbas(dlist_t *slices,
1642  *			dlist_t **usable)
1643  *
1644  * INPUT:	disks	- a list of usable disks.
1645  *
1646  * OUTPUT:	usable	- a populated list of usable HBAs.
1647  *
1648  * RETURNS:	int	- 0 on success
1649  *			 !0 otherwise
1650  *
1651  * PURPOSE:	Examines usable disk list and derives the list of usable HBAs.
1652  *
1653  */
1654 static int
1655 generate_usable_hbas(
1656 	dlist_t *disks,
1657 	dlist_t	**usable)
1658 {
1659 	dlist_t	*iter;
1660 	int	error = 0;
1661 
1662 	/*
1663 	 * for each usable disk, follow its HBA connections and
1664 	 * add them to the list of usable HBAs.
1665 	 */
1666 	for (iter = disks; (iter != NULL) && (error == 0); iter = iter->next) {
1667 
1668 	    dm_descriptor_t	dp = NULL;
1669 	    dlist_t 		*hbas = NULL;
1670 	    dlist_t		*iter2 = NULL;
1671 
1672 	    dp = (uintptr_t)iter->obj;
1673 
1674 	    error = disk_get_hbas(dp, &hbas);
1675 	    if (error == 0) {
1676 
1677 		for (iter2 = hbas;
1678 		    (iter2 != NULL) && (error == 0);
1679 		    iter2 = iter2->next) {
1680 
1681 		    dm_descriptor_t	hba = (uintptr_t)iter2->obj;
1682 		    dlist_t		*item = NULL;
1683 
1684 		    /* scan list of usable HBAs and see if known */
1685 		    if (dlist_contains(*usable,
1686 			(void*)hba, compare_descriptor_names) == B_TRUE) {
1687 			/* known HBA, continue to next HBA/alias */
1688 			continue;
1689 		    }
1690 
1691 		    /* add this HBA to the usable list */
1692 		    if ((item = dlist_new_item((void *)hba)) == NULL) {
1693 			error = ENOMEM;
1694 		    } else {
1695 			*usable =
1696 			    dlist_insert_ordered(item, *usable,
1697 				    ASCENDING, compare_desc_display_names);
1698 		    }
1699 		}
1700 	    }
1701 
1702 	    dlist_free_items(hbas, NULL);
1703 	}
1704 
1705 	return (error);
1706 }
1707 
1708 /*
1709  * FUNCTION:	check_slice_usage(char *dsname, dm_descriptor_t slice,
1710  *			dm_descriptor_t disk, boolean_t *avail,
1711  *			dlist_t **bad, dlist_t **classes)
1712  *
1713  * INPUT:	dsname	- a char * diskset name.
1714  *		slice	- a dm_descriptor_t handle for a known slices.
1715  *		disk	- a dm_descriptor_t handle the slice's disk.
1716  *
1717  * OUTPUT:	avail	- a boolean_t to hold the slice's availability.
1718  *		bad	- pointer to a list of bad/unusable slices,
1719  *				possibly updated if the input slice
1720  *				was determined to be inaccessible.
1721  *		classes	- pointer to a list of slice_class_t structs,
1722  *				possibly updated to include the input slice
1723  *				if it has a known use.
1724  *
1725  * RETURNS:	int	- 0 on success
1726  *			 !0 otherwise.
1727  *
1728  * PURPOSE:	Handles the details of
1729  *		determining usage and/or availability of a single slice.
1730  *
1731  *		Queries the device library for the input slice's detectable
1732  *		usage status.
1733  *
1734  *		If the slice has a detected usage, its name is added to
1735  *		the appropriate slice_class_t list in the input list of
1736  *		slice classes, this is only done if verbose output was
1737  * 		requested.
1738  */
1739 static int
1740 check_slice_usage(
1741 	char		*dsname,
1742 	dm_descriptor_t slice,
1743 	dm_descriptor_t disk,
1744 	boolean_t	*avail,
1745 	dlist_t		**bad,
1746 	dlist_t		**classes)
1747 {
1748 	boolean_t	online = B_FALSE;
1749 	boolean_t	used = B_FALSE;
1750 	nvlist_t	*stats = NULL;
1751 	char		*name = NULL;
1752 	char		*used_by = NULL;
1753 	char		*use_detail = NULL;
1754 	int		error = 0;
1755 
1756 	*avail = B_FALSE;
1757 
1758 	if (((error = get_display_name(slice, &name)) != 0) ||
1759 	    (error = disk_get_is_online(disk, &online))) {
1760 	    return (error);
1761 	}
1762 
1763 	/*
1764 	 * if the disk is known to be offline, skip getting status
1765 	 * for the slice since it will just fail and return ENODEV.
1766 	 */
1767 	if (online != B_TRUE) {
1768 	    error = ENODEV;
1769 	} else {
1770 	    stats = dm_get_stats(slice, DM_SLICE_STAT_USE, &error);
1771 	}
1772 
1773 	if (error != 0) {
1774 	    if (error == ENODEV) {
1775 		dlist_t *item = dlist_new_item((void *)slice);
1776 		oprintf(OUTPUT_TERSE,
1777 			gettext("Warning: unable to get slice information "
1778 				"for %s, it will not be used.\n"), name);
1779 
1780 		if (item == NULL) {
1781 		    error = ENOMEM;
1782 		} else {
1783 		    error = 0;
1784 		    *bad = dlist_insert_ordered(item, *bad, ASCENDING,
1785 			    compare_desc_display_names);
1786 		}
1787 	    } else {
1788 		oprintf(OUTPUT_TERSE,
1789 			gettext("check_slice_usage: dm_get_stats for "
1790 				"%s failed %d\n"),
1791 			name, error);
1792 	    }
1793 
1794 	    return (error);
1795 	}
1796 
1797 	/*
1798 	 * check if/how the slice is currently being used,
1799 	 * device library provides this info in the nvpair_t list:
1800 	 *
1801 	 *   stat_type is DM_SLICE_STAT_USE
1802 	 *	used_by:	string (mount, svm, lu, vxvm, fs)
1803 	 *	used_name:	string
1804 	 *
1805 	 */
1806 	if (stats != NULL) {
1807 	    error = get_string(stats, DM_USED_BY, &used_by);
1808 	    if (error != 0) {
1809 		if (error == ENOENT) {
1810 		    used_by = NULL;
1811 		    error = 0;
1812 		} else {
1813 		    oprintf(OUTPUT_TERSE,
1814 			    gettext("check_slice_usage: dm_get_stats.%s for "
1815 				    "%s failed %d\n"),
1816 			    DM_USED_BY, name, error);
1817 		}
1818 	    }
1819 
1820 	    if (error == 0) {
1821 		error = get_string(stats, DM_USED_NAME, &use_detail);
1822 		if (error != 0) {
1823 		    if (error == ENOENT) {
1824 			use_detail = NULL;
1825 			error = 0;
1826 		    } else {
1827 			oprintf(OUTPUT_TERSE,
1828 				gettext("check_slice_usage: "
1829 					"dm_get_stats.%s for "
1830 					"%s failed %d\n"),
1831 					DM_USED_NAME, name, error);
1832 		    }
1833 		}
1834 	    }
1835 	}
1836 
1837 	if ((error == 0) && (used_by != NULL) && (used_by[0] != '\0')) {
1838 
1839 	    /* was detected usage SVM? */
1840 	    if (string_case_compare(used_by, DM_USE_SVM) == 0) {
1841 
1842 		/* check use_detail, it is in the form diskset:name */
1843 		if (strncmp("diskset:", use_detail, 8) == 0) {
1844 
1845 		    /* check disk set name */
1846 		    char *str = strrchr(use_detail, ':');
1847 		    if ((str != NULL) &&
1848 			    (string_case_compare(str+1, dsname) == 0)) {
1849 
1850 			/* slice in the right diskset */
1851 			error = check_svm_slice_usage(
1852 				dsname, slice, disk, &used, classes);
1853 
1854 		    } else {
1855 
1856 			/* slice in other diskset */
1857 			save_slice_classification(
1858 				dsname, slice, disk, used_by, use_detail,
1859 				classes);
1860 			used = B_TRUE;
1861 		    }
1862 
1863 		} else {
1864 
1865 		    /* slice is volume component */
1866 		    save_slice_classification(
1867 			    dsname, slice, disk, used_by, use_detail,
1868 			    classes);
1869 		    used = B_TRUE;
1870 		}
1871 
1872 	    } else {
1873 
1874 		/* save usage */
1875 		save_slice_classification(
1876 			dsname, slice, disk, used_by, use_detail,
1877 			classes);
1878 		used = B_TRUE;
1879 	    }
1880 	}
1881 
1882 	nvlist_free(stats);
1883 
1884 	if (error == 0) {
1885 	    if (used == B_TRUE) {
1886 		*avail = B_FALSE;
1887 	    } else {
1888 		*avail = B_TRUE;
1889 	    }
1890 	}
1891 
1892 	return (error);
1893 }
1894 
1895 /*
1896  * FUNCTION:	check_svm_slice_usage(char *dsname, dm_descriptor_t slice,
1897  *			dm_descriptor_t disk, boolean_t *used,
1898  *			dlist_t **classes)
1899  *
1900  * INPUT:	dsname	- a char * diskset name.
1901  *		slice	- a dm_descriptor_t handle for a known slices.
1902  *		disk	- a dm_descriptor_t handle the slice's disk.
1903  *
1904  * OUTPUT:	used	- a boolean_t to hold the slice usage status.
1905  *		classes	- pointer to a list of slice_class_t possibly updated
1906  *				with the input slice's SVM specific usage
1907  *				classification.
1908  *
1909  * RETURNS:	int	- 0 on success
1910  *			 !0 otherwise.
1911  *
1912  * PURPOSE:	Handles the finer details of
1913  *		a single slice is being used in the context of SVM.
1914  *
1915  *		Currently, one thing is checked:
1916  *
1917  *		1. determine if the slice is reserved for metadb replicas.
1918  *		   The convention for disks in disksets is that a single slice
1919  *		   (index 6 or 7) is set aside for metadb replicas.
1920  *
1921  *		If this condition does not hold, the slice is considered
1922  *		available for use by layout and 'used' is set to B_FALSE.
1923  */
1924 static int
1925 check_svm_slice_usage(
1926 	char		*dsname,
1927 	dm_descriptor_t slice,
1928 	dm_descriptor_t disk,
1929 	boolean_t	*used,
1930 	dlist_t		**classes)
1931 {
1932 	boolean_t is_replica = B_FALSE;
1933 	uint32_t index = 0;
1934 	char	*diskname = NULL;
1935 	int	error = 0;
1936 
1937 	((error = slice_get_index(slice, &index)) != 0) ||
1938 	(error = get_display_name(disk, &diskname)) ||
1939 	(error = is_reserved_replica_slice_index(
1940 		dsname, diskname, index, &is_replica));
1941 
1942 	if (error == 0) {
1943 	    if (is_replica == B_TRUE) {
1944 		/* is replica slice -> used */
1945 		save_slice_classification(dsname, slice, disk, DM_USE_SVM,
1946 			gettext("reserved for metadb replicas"), classes);
1947 		*used = B_TRUE;
1948 	    } else {
1949 		*used = B_FALSE;
1950 	    }
1951 	}
1952 
1953 	return (error);
1954 }
1955 
1956 /*
1957  * FUNCTION:	save_slice_classification(char *dsname, dm_descriptor_t slice,
1958  *			dm_descriptor_t disk, char *used_by, char *usage_detail,
1959  *			dlist_t **classes)
1960  *
1961  * INPUT:	dsname	- a char * disk set name
1962  *		slice	- a dm_descriptor_t slice handle.
1963  *		disk	- a dm_descriptor_t handle for the slice's disk.
1964  *		used_by - a char * usage classification.
1965  *		usage_detail - a char * usage description for the slice.
1966  *
1967  * OUTPUT:	classes	- a list of slice_class_t updated to hold a usage
1968  *				entry for the input slicexs.
1969  *
1970  * SIDEEFFECT:	adds the input slice to the list of known, used slices.
1971  *
1972  * RETURNS:	int	- 0 on success
1973  *			 !0 otherwise.
1974  *
1975  * PURPOSE:	Adds an entry to the
1976  *		appropriate slice_class_t list of slices.  If there is
1977  *		not an appropriate slice_class_t entry in the input list
1978  *		of classes, one is added.
1979  *
1980  *		As a performance optimization the slice usage classification
1981  *		information is only saved if verbose output was requested by
1982  *		the user.
1983  */
1984 static int
1985 save_slice_classification(
1986 	char		*dsname,
1987 	dm_descriptor_t	slice,
1988 	dm_descriptor_t	disk,
1989 	char		*usage,
1990 	char		*usage_detail,
1991 	dlist_t		**classes)
1992 {
1993 	int		error = 0;
1994 
1995 	error = add_used_slice(slice);
1996 
1997 	if ((error == 0) && (get_max_verbosity() >= OUTPUT_VERBOSE)) {
1998 
1999 	    dlist_t		*iter;
2000 	    dlist_t		*item;
2001 	    slice_class_t 	*class = NULL;
2002 
2003 	    /* locate class struct matching 'usage' */
2004 	    for (iter = *classes; iter != NULL; iter = iter->next) {
2005 		class = (slice_class_t *)iter->obj;
2006 		if (string_case_compare(usage, class->usage) == 0) {
2007 		    break;
2008 		}
2009 	    }
2010 
2011 	    if (iter == NULL) {
2012 		/* add a new class to the list of classes */
2013 		class = (slice_class_t *)calloc(1, sizeof (slice_class_t));
2014 		if (class == NULL) {
2015 		    error = ENOMEM;
2016 		} else {
2017 		    class->usage = strdup(usage);
2018 		    if (class->usage == NULL) {
2019 			free(class);
2020 			class = NULL;
2021 			error = ENOMEM;
2022 		    } else {
2023 			item = dlist_new_item((void *)class);
2024 			if (item == NULL) {
2025 			    free(class->usage);
2026 			    free(class);
2027 			    class = NULL;
2028 			    error = ENOMEM;
2029 			} else {
2030 			    *classes = dlist_append(item, *classes, AT_TAIL);
2031 			}
2032 		    }
2033 		}
2034 	    }
2035 
2036 	    if ((error == 0) && (class != NULL)) {
2037 
2038 		char buf[BUFSIZ];
2039 		char *dup = NULL;
2040 		char *slicename = NULL;
2041 
2042 		(void) get_display_name(slice, &slicename);
2043 		(void) snprintf(buf, BUFSIZ-1, "  %s: %s",
2044 			slicename, usage_detail);
2045 		if ((dup = strdup(buf)) == NULL) {
2046 		    error = ENOMEM;
2047 		} else {
2048 		    if ((item = dlist_new_item((void *)dup)) == NULL) {
2049 			free(dup);
2050 			error = ENOMEM;
2051 		    } else {
2052 			class->sliceinfo =
2053 			    dlist_insert_ordered(
2054 				    item, class->sliceinfo,
2055 				    ASCENDING, compare_strings);
2056 		    }
2057 		}
2058 	    }
2059 	}
2060 
2061 	return (error);
2062 }
2063 
2064 /*
2065  * FUNCTION:	print_usable_devices()
2066  *
2067  * PURPOSE:	Print out the devices determined to be available for
2068  *		use by layout.
2069  *
2070  *		Iterates the lists of usable slices, disks and HBAs
2071  *		and prints out their CTD and device names.
2072  */
2073 static void
2074 print_usable_devices()
2075 {
2076 	int	i = 0;
2077 
2078 	struct {
2079 		char *msg;
2080 		dlist_t *list;
2081 	}	devs[3];
2082 
2083 	devs[0].msg = gettext("HBA/Controllers");
2084 	devs[0].list = _usable_hbas;
2085 	devs[1].msg = gettext("disks");
2086 	devs[1].list = _usable_disks;
2087 	devs[2].msg = gettext("slices");
2088 	devs[2].list = _usable_slices;
2089 
2090 	for (i = 0; i < 3; i++) {
2091 
2092 	    oprintf(OUTPUT_VERBOSE,
2093 		    gettext("\n  These %s are usable:\n\n"),
2094 		    devs[i].msg);
2095 
2096 	    print_device_list(devs[i].list);
2097 	}
2098 }
2099 
2100 /*
2101  * FUNCTION:	print_device_list(dlist_t *devices)
2102  *
2103  * INPUT:	devices	- a list of device descriptor handles
2104  *
2105  * PURPOSE:	A helper for the print_XXX_devices() routines which iterates
2106  *		the input list and prints out each device name, CTD name and
2107  *		alias(es).
2108  */
2109 static void
2110 print_device_list(
2111 	dlist_t *devices)
2112 {
2113 	dlist_t *iter = NULL;
2114 
2115 	for (iter = devices; iter != NULL; iter = iter->next) {
2116 
2117 	    dm_descriptor_t device = ((uintptr_t)iter->obj);
2118 	    char	*name = NULL;
2119 	    char	*ctd = NULL;
2120 	    dlist_t	*aliases = NULL;
2121 
2122 	    (void) get_display_name(device, &ctd);
2123 	    (void) get_name(device, &name);
2124 	    oprintf(OUTPUT_VERBOSE,
2125 		    "    %-25s %s\n", (ctd != NULL ? ctd : ""), name);
2126 
2127 	    (void) get_aliases(device, &aliases);
2128 	    for (; aliases != NULL; aliases = aliases->next) {
2129 		oprintf(OUTPUT_VERBOSE,
2130 			gettext("      (alias: %s)\n"),
2131 			(char *)aliases->obj);
2132 	    }
2133 
2134 	    dlist_free_items(aliases, free);
2135 	}
2136 }
2137 
2138 /*
2139  * FUNCTION:	print_unusable_devices(
2140  *			dlist_t *bad_slices, dlist_t *bad_disks,
2141  *			dlist_t	*used_classes)
2142  *
2143  * INPUT:	used_classes - a list of slice_class_t structs
2144  *
2145  * PURPOSE:	Print out the devices determined to be unavailable for
2146  *		use by layout.
2147  *
2148  *		Iterates the input list of slice classifications and prints
2149  *		out a description of the class and the slices so classified.
2150  *
2151  *		Also iterates the lists of bad slices and disks (those that
2152  *		libdiskmgt returned descriptors for but cannot be accessed)
2153  *		and notes them as unusable.
2154  */
2155 static void
2156 print_unusable_devices(
2157 	dlist_t	*bad_slices,
2158 	dlist_t	*bad_disks,
2159 	dlist_t	*used_classes)
2160 {
2161 	dlist_t	*iter = NULL;
2162 	dlist_t	*slices = NULL;
2163 	char	*preamble;
2164 
2165 	struct {
2166 		char *msg;
2167 		dlist_t *list;
2168 	}	devs[2];
2169 
2170 	/* report bad disks and slices */
2171 	devs[0].msg = gettext("disks");
2172 	devs[0].list = bad_disks;
2173 	devs[1].msg = gettext("slices");
2174 	devs[1].list = bad_slices;
2175 
2176 	if (bad_disks != NULL) {
2177 	    oprintf(OUTPUT_VERBOSE,
2178 #if defined(sparc)
2179 		    gettext("\n  These disks are not usable, they may "
2180 			    "may be offline or cannot be accessed:\n\n"));
2181 #elif defined(i386)
2182 		    gettext("\n  These disks are not usable, they may "
2183 			    "may be offline,\n  missing a Solaris FDISK "
2184 			    "partition or cannot be accessed:\n\n"));
2185 #endif
2186 	    print_device_list(bad_disks);
2187 	}
2188 
2189 	if (bad_slices != NULL) {
2190 	    oprintf(OUTPUT_VERBOSE, gettext(
2191 		"\n  These slices, and subsequently the disks on which they\n"
2192 		"reside, are not usable, they cannot be accessed:\n\n"));
2193 	    print_device_list(bad_slices);
2194 	}
2195 
2196 	/* report used slices and usages */
2197 	preamble = gettext("\n  These slices are not usable, %s:\n\n");
2198 	for (iter = used_classes; iter != NULL; iter = iter->next) {
2199 	    slice_class_t *class = (slice_class_t *)iter->obj;
2200 
2201 	    if (class->sliceinfo != NULL) {
2202 
2203 		oprintf(OUTPUT_VERBOSE, preamble,
2204 			get_slice_usage_msg(class->usage));
2205 
2206 		slices = class->sliceinfo;
2207 		for (; slices != NULL; slices = slices->next) {
2208 		    oprintf(OUTPUT_VERBOSE, "  %s\n", (char *)slices->obj);
2209 		}
2210 	    }
2211 	}
2212 
2213 }
2214 
2215 /*
2216  * FUNCTION:	char * get_slice_usage_msg(char *usage)
2217  *
2218  * INPUT:	usage - char * string representing a slice usage classification
2219  *
2220  * OUTPUT:	char * "friendly" usage message
2221  *
2222  * PURPOSE:	the input usage string comes from libdiskmgt and is very terse.
2223  *
2224  *		Convert it into a friendlier usage description suitable for user
2225  *		consumption.
2226  */
2227 static char *
2228 get_slice_usage_msg(
2229 	char *usage)
2230 {
2231 	char *str = NULL;
2232 
2233 	if (string_case_compare(usage, DM_USE_MOUNT) == 0) {
2234 	    str = gettext("they have mounted filesystems");
2235 	} else if (string_case_compare(usage, DM_USE_FS) == 0) {
2236 	    str = gettext("they appear to have unmounted filesystems");
2237 	} else if (string_case_compare(usage, DM_USE_SVM) == 0) {
2238 	    str = gettext("they are utilized by SVM");
2239 	} else if (string_case_compare(usage, DM_USE_VXVM) == 0) {
2240 	    str = gettext("they are utilized by VxVm");
2241 	} else if (string_case_compare(usage, DM_USE_LU) == 0) {
2242 	    str = gettext("they are utilized by LiveUpgrade");
2243 	} else if (string_case_compare(usage, DM_USE_DUMP) == 0) {
2244 	    str = gettext("they are reserved as dump devices");
2245 	} else if (string_case_compare(usage, USE_DISKSET) == 0) {
2246 	    str = gettext("they have disk set issues");
2247 	} else {
2248 	    /* libdiskmgt has detected a usage unknown to layout */
2249 	    str = usage;
2250 	}
2251 
2252 	return (str);
2253 }
2254 
2255 /*
2256  * FUNCTION:	set_alias(dm_descriptor_t desc, char *alias)
2257  *
2258  * INPUT:	desc	- a dm_descriptor_t handle.
2259  *		alias	- a char * alias for the device represented
2260  *				by the descriptor.
2261  *
2262  * RETURNS:	int	- 0 on success
2263  *			 !0 otherwise
2264  *
2265  * PURPOSE:	Adds the specified alias to the known aliases for the
2266  *		device associated with the input descriptor.
2267  */
2268 int
2269 set_alias(
2270 	dm_descriptor_t desc,
2271 	char	*alias)
2272 {
2273 	nvlist_t	*attrs = NULL;
2274 	char		**old_aliases = NULL;
2275 	char		**new_aliases = NULL;
2276 	uint_t		nelem = 0;
2277 	int		error = 0;
2278 	int		i = 0;
2279 
2280 	if ((error = get_cached_attributes(desc, &attrs)) != 0) {
2281 	    return (error);
2282 	}
2283 
2284 	if ((error = get_string_array(
2285 	    attrs, ATTR_DEVICE_ALIASES, &old_aliases, &nelem)) != 0) {
2286 	    if (error != ENOENT) {
2287 		return (error);
2288 	    }
2289 	    /* no aliases yet */
2290 	    error = 0;
2291 	}
2292 
2293 	/* add new alias */
2294 	new_aliases = (char **)calloc(MAX_ALIASES, sizeof (char *));
2295 	if (new_aliases != NULL) {
2296 
2297 	    for (i = 0; i < nelem && i < MAX_ALIASES; i++) {
2298 		char *dup = strdup(old_aliases[i]);
2299 		if (dup != NULL) {
2300 		    new_aliases[i] = dup;
2301 		} else {
2302 		    error = ENOMEM;
2303 		}
2304 	    }
2305 
2306 	    if (error == 0) {
2307 		if (i == MAX_ALIASES) {
2308 		    volume_set_error(
2309 			    gettext("Maximum number of device aliases "
2310 				    "(8) reached\n"),
2311 			    MAX_ALIASES);
2312 		    error = -1;
2313 
2314 		} else {
2315 		    new_aliases[i] = alias;
2316 		    error = set_string_array(attrs, ATTR_DEVICE_ALIASES,
2317 			    new_aliases, i + 1);
2318 		}
2319 	    }
2320 
2321 	    free(new_aliases);
2322 	}
2323 
2324 	if (error == 0) {
2325 	    /* cache descriptor under this alias */
2326 	    error = add_cached_descriptor(alias, desc);
2327 	}
2328 
2329 	return (error);
2330 }
2331 
2332 /*
2333  * FUNCTION:	get_aliases(dm_descriptor_t desc, dlist_t **list)
2334  *
2335  * INPUT:	desc	- a dm_descriptor_t handle.
2336  *
2337  * OUTPUT:	list	- a dlist_t list pointing to the list of
2338  *				aliases associated with the device
2339  *				represented by the descriptor.
2340  *
2341  * RETURNS:	int	- 0 on success
2342  *			 !0 otherwise
2343  *
2344  * PURPOSE:	Retrieves aliases for the input descriptor and
2345  *		appends them to the input list.
2346  *
2347  *		The list of returned items must be freed by calling
2348  *		dlist_free_items(list, free)
2349  */
2350 int
2351 get_aliases(
2352 	dm_descriptor_t desc,
2353 	dlist_t		**list)
2354 {
2355 	nvlist_t	*attrs = NULL;
2356 	char		**aliases = NULL;
2357 	uint_t		nelem = 0;
2358 	int		error = 0;
2359 	int		i;
2360 
2361 	if ((error = get_cached_attributes(desc, &attrs)) != 0) {
2362 	    return (error);
2363 	}
2364 
2365 	if ((error = get_string_array(
2366 	    attrs, ATTR_DEVICE_ALIASES, &aliases, &nelem)) != 0) {
2367 	    if (error == ENOENT) {
2368 		/* no aliases */
2369 		return (0);
2370 	    }
2371 	}
2372 
2373 	for (i = 0; i < nelem; i++) {
2374 	    dlist_t *item;
2375 	    char *dup;
2376 
2377 	    if ((dup = strdup(aliases[i])) == NULL) {
2378 		error = ENOMEM;
2379 		break;
2380 	    }
2381 
2382 	    if ((item = dlist_new_item(dup)) == NULL) {
2383 		free(dup);
2384 		error = ENOMEM;
2385 		break;
2386 	    }
2387 
2388 	    *list = dlist_append(item, *list, AT_TAIL);
2389 	}
2390 
2391 	return (error);
2392 }
2393 
2394 /*
2395  * FUNCTION:	compare_start_blocks(
2396  *			void *obj1, void *obj2)
2397  *
2398  * INPUT:	desc1	- opaque pointer to a dm_descriptor_t
2399  * 		desc2	- opaque pointer to a dm_descriptor_t
2400  *
2401  * RETURNS:	int	- <0 - if desc1.stblk < desc2.stblk
2402  *			   0 - if desc1.stblk == desc2.stblk
2403  *			  >0 - if desc1.stblk > desc.stblk
2404  *
2405  * PURPOSE:	dlist_t helper which compares the start blocks of
2406  *		the two input dm_descriptor_t slice handles.
2407  */
2408 static int
2409 compare_start_blocks(
2410 	void	*desc1,
2411 	void	*desc2)
2412 {
2413 	uint64_t stblk1 = 0;
2414 	uint64_t stblk2 = 0;
2415 
2416 	assert(desc1 != (dm_descriptor_t)0);
2417 	assert(desc2 != (dm_descriptor_t)0);
2418 
2419 	(void) slice_get_start_block((uintptr_t)desc1, &stblk1);
2420 	(void) slice_get_start_block((uintptr_t)desc2, &stblk2);
2421 
2422 	return (stblk1 - stblk2);
2423 }
2424 
2425 /*
2426  * FUNCTION:	compare_desc_display_names(
2427  *			void *desc1, void *desc2)
2428  *
2429  * INPUT:	desc1	- opaque pointer to a dm_descriptor_t
2430  * 		desc2	- opaque pointer to a dm_descriptor_t
2431  *
2432  * RETURNS:	int	- <0 - if desc1.name < desc2.name
2433  *			   0 - if desc1.name == desc2.name
2434  *			  >0 - if desc1.name > desc.name
2435  *
2436  * PURPOSE:	dlist_t helper which compares the CTD names of the
2437  *		two input dm_descriptor_t objects.
2438  */
2439 static int
2440 compare_desc_display_names(
2441 	void	*desc1,
2442 	void	*desc2)
2443 {
2444 	char	*name1 = NULL;
2445 	char	*name2 = NULL;
2446 
2447 	assert(desc1 != (dm_descriptor_t)0);
2448 	assert(desc2 != (dm_descriptor_t)0);
2449 
2450 	(void) get_display_name((uintptr_t)desc1, &name1);
2451 	(void) get_display_name((uintptr_t)desc2, &name2);
2452 
2453 	return (string_case_compare(name1, name2));
2454 }
2455