10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*62Sjeanm * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <limits.h>
300Sstevel@tonic-gate #include <libdiskmgt.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include <meta.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #define _LAYOUT_DISCOVERY_C
360Sstevel@tonic-gate
370Sstevel@tonic-gate #include "volume_dlist.h"
380Sstevel@tonic-gate #include "volume_error.h"
390Sstevel@tonic-gate #include "volume_nvpair.h"
400Sstevel@tonic-gate #include "volume_output.h"
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include "layout_device_cache.h"
430Sstevel@tonic-gate #include "layout_device_util.h"
440Sstevel@tonic-gate #include "layout_dlist_util.h"
450Sstevel@tonic-gate #include "layout_discovery.h"
460Sstevel@tonic-gate #include "layout_request.h"
470Sstevel@tonic-gate #include "layout_slice.h"
480Sstevel@tonic-gate #include "layout_svm_util.h"
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * lists of device dm_descriptor_t handles discovered during
520Sstevel@tonic-gate * the initial system probe. Lists are populated by
530Sstevel@tonic-gate * discover_known_devices.
540Sstevel@tonic-gate *
550Sstevel@tonic-gate * "bad" slices are those that are known to libdiskmgt but
560Sstevel@tonic-gate * cannot be accessed. An example would be a slice that has
570Sstevel@tonic-gate * disappeared due to disk re-slicing: libdiskmgt may have a
580Sstevel@tonic-gate * cached handle for it, but the slice no longer exists.
590Sstevel@tonic-gate *
600Sstevel@tonic-gate * "bad" disks are thoese that are known to libdiskmgt but
610Sstevel@tonic-gate * cannot be accessed. An example would be a disk that has
620Sstevel@tonic-gate * failed or has gone offline: libdiskmgt may have a cached
630Sstevel@tonic-gate * handle for it, but the disk does not respond.
640Sstevel@tonic-gate */
650Sstevel@tonic-gate static dlist_t *_bad_slices = NULL;
660Sstevel@tonic-gate static dlist_t *_bad_disks = NULL;
670Sstevel@tonic-gate
680Sstevel@tonic-gate static dlist_t *_known_slices = NULL;
690Sstevel@tonic-gate static dlist_t *_known_disks = NULL;
700Sstevel@tonic-gate static dlist_t *_known_hbas = NULL;
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * helper functions for building known device lists, used by
740Sstevel@tonic-gate * discover_known_devices.
750Sstevel@tonic-gate */
760Sstevel@tonic-gate static int generate_known_slices(dlist_t *disks, dlist_t **known,
770Sstevel@tonic-gate dlist_t **bad);
780Sstevel@tonic-gate static int generate_known_disks(dlist_t **known, dlist_t **bad);
790Sstevel@tonic-gate static int generate_known_hbas(dlist_t *disks, dlist_t **known);
800Sstevel@tonic-gate static int generate_known_hba_name(
810Sstevel@tonic-gate dm_descriptor_t hba,
820Sstevel@tonic-gate dm_descriptor_t alias,
830Sstevel@tonic-gate dm_descriptor_t disk);
840Sstevel@tonic-gate
850Sstevel@tonic-gate static void print_known_devices();
860Sstevel@tonic-gate static void print_device_list(dlist_t *devices);
870Sstevel@tonic-gate
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate * lists of device dm_descriptor_t handles that are usable by layout.
900Sstevel@tonic-gate * These devices must still pass the user specified available/unavailable
910Sstevel@tonic-gate * filter before they're actually considered available.
920Sstevel@tonic-gate *
930Sstevel@tonic-gate * Lists are populated by discover_usable_devices.
940Sstevel@tonic-gate */
950Sstevel@tonic-gate static dlist_t *_usable_slices = NULL;
960Sstevel@tonic-gate static dlist_t *_usable_disks = NULL;
970Sstevel@tonic-gate static dlist_t *_usable_hbas = NULL;
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * private flag that remembers if any HBA is known to support MPXIO
1010Sstevel@tonic-gate */
1020Sstevel@tonic-gate static boolean_t _mpxio_enabled = B_FALSE;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate * The slice_class struct is used to group slices by usage class.
1060Sstevel@tonic-gate */
1070Sstevel@tonic-gate typedef struct {
1080Sstevel@tonic-gate char *usage; /* usage description */
1090Sstevel@tonic-gate dlist_t *sliceinfo; /* list with info about each slice with usage */
1100Sstevel@tonic-gate } slice_class_t;
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate #define USE_DISKSET "diskset"
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate static int check_slice_usage(
1150Sstevel@tonic-gate char *dsname,
1160Sstevel@tonic-gate dm_descriptor_t slice,
1170Sstevel@tonic-gate dm_descriptor_t disk,
1180Sstevel@tonic-gate boolean_t *avail,
1190Sstevel@tonic-gate dlist_t **bad,
1200Sstevel@tonic-gate dlist_t **classes);
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate static int check_svm_slice_usage(
1230Sstevel@tonic-gate char *dsname,
1240Sstevel@tonic-gate dm_descriptor_t slice,
1250Sstevel@tonic-gate dm_descriptor_t disk,
1260Sstevel@tonic-gate boolean_t *avail,
1270Sstevel@tonic-gate dlist_t **classes);
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate static int save_slice_classification(
1300Sstevel@tonic-gate char *dsname,
1310Sstevel@tonic-gate dm_descriptor_t slice,
1320Sstevel@tonic-gate dm_descriptor_t disk,
1330Sstevel@tonic-gate char *usage,
1340Sstevel@tonic-gate char *usage_detail,
1350Sstevel@tonic-gate dlist_t **classes);
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate static int generate_usable_disks_and_slices_in_local_set(
1380Sstevel@tonic-gate dlist_t **classes,
1390Sstevel@tonic-gate dlist_t **bad_disks,
1400Sstevel@tonic-gate dlist_t **usable_disks,
1410Sstevel@tonic-gate dlist_t **usable_slices);
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate static int generate_usable_disks_and_slices_in_named_set(
1440Sstevel@tonic-gate char *dsname,
1450Sstevel@tonic-gate dlist_t **classes,
1460Sstevel@tonic-gate dlist_t **bad_slices,
1470Sstevel@tonic-gate dlist_t **usable_disks,
1480Sstevel@tonic-gate dlist_t **usable_slices);
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate static int create_usable_slices(
1510Sstevel@tonic-gate dm_descriptor_t disk,
1520Sstevel@tonic-gate dlist_t *used,
1530Sstevel@tonic-gate dlist_t *unused,
1540Sstevel@tonic-gate dlist_t **usable);
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate static int add_new_usable(
1570Sstevel@tonic-gate dm_descriptor_t disk,
1580Sstevel@tonic-gate uint64_t stblk,
1590Sstevel@tonic-gate uint64_t nblks,
1600Sstevel@tonic-gate dlist_t **next_unused,
1610Sstevel@tonic-gate dlist_t **usable);
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate static int update_slice_attributes(
1640Sstevel@tonic-gate dm_descriptor_t slice,
1650Sstevel@tonic-gate uint64_t stblk,
1660Sstevel@tonic-gate uint64_t nblks,
1670Sstevel@tonic-gate uint64_t nbytes);
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate static int generate_usable_hbas(
1700Sstevel@tonic-gate dlist_t *disks,
1710Sstevel@tonic-gate dlist_t **usable);
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate static void print_usable_devices();
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate static void print_unusable_devices(
1760Sstevel@tonic-gate dlist_t *badslices,
1770Sstevel@tonic-gate dlist_t *baddisks,
1780Sstevel@tonic-gate dlist_t *usedslices);
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate static char *get_slice_usage_msg(
1810Sstevel@tonic-gate char *usage);
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * virtual slices...
1850Sstevel@tonic-gate */
1860Sstevel@tonic-gate static int generate_virtual_slices(
1870Sstevel@tonic-gate dlist_t *avail_disks_local_set,
1880Sstevel@tonic-gate dlist_t **usable);
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate * multipathed disks have aliases, as do slices on those disks.
1920Sstevel@tonic-gate * these need to be tracked since the user may specify them.
1930Sstevel@tonic-gate * A multi-pathed disk is one connected to the system thru
1940Sstevel@tonic-gate * more than one physical HBA, each connection gets a distinct
1950Sstevel@tonic-gate * name in the device tree and they're all more or less equivalent.
1960Sstevel@tonic-gate * No indication as to how many possible physical connections a
1970Sstevel@tonic-gate * disk may have, so we pick an arbitrary number of aliases to
1980Sstevel@tonic-gate * support. There is nothing significant about this number,
1990Sstevel@tonic-gate * it just controls the number of alias slots that get allocated.
2000Sstevel@tonic-gate */
2010Sstevel@tonic-gate #define MAX_ALIASES 8
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate * attribute name for layout private information stored in
2050Sstevel@tonic-gate * device nvpair attribute lists.
2060Sstevel@tonic-gate */
2070Sstevel@tonic-gate static char *ATTR_DEVICE_ALIASES = "layout_device_aliases";
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate static int compare_start_blocks(
2100Sstevel@tonic-gate void *desc1, void *desc2);
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate static int compare_desc_display_names(
2130Sstevel@tonic-gate void *desc1, void *desc2);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate * FUNCTION: is_mpxio_enabled()
2170Sstevel@tonic-gate *
2180Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE - if MPXIO appears enabled for the system
2190Sstevel@tonic-gate * B_FALSE - otherwise
2200Sstevel@tonic-gate *
2210Sstevel@tonic-gate * PURPOSE: returns the value of _mpxio_enabled which is set to B_TRUE
2220Sstevel@tonic-gate * during system configuration discovery if any of the knwon
2230Sstevel@tonic-gate * HBAs advertises itself as a "multiplex" controller.
2240Sstevel@tonic-gate */
2250Sstevel@tonic-gate boolean_t
is_mpxio_enabled()2260Sstevel@tonic-gate is_mpxio_enabled()
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate return (_mpxio_enabled);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate * FUNCTION: discover_known_devices()
2330Sstevel@tonic-gate *
2340Sstevel@tonic-gate * SIDEEFFECT: populates the module private lists of known devices
2350Sstevel@tonic-gate * (_known_slices, _known_disks, _known_hbas).
2360Sstevel@tonic-gate *
2370Sstevel@tonic-gate * All known devices will also have had their CTD
2380Sstevel@tonic-gate * short names inferred and stored.
2390Sstevel@tonic-gate *
2400Sstevel@tonic-gate * RETURNS: int - 0 on success
2410Sstevel@tonic-gate * !0 otherwise
2420Sstevel@tonic-gate *
2430Sstevel@tonic-gate * PURPOSE: Load physical devices discovered thru libdiskmgt.
2440Sstevel@tonic-gate */
2450Sstevel@tonic-gate int
discover_known_devices()2460Sstevel@tonic-gate discover_known_devices()
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate int error = 0;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
2510Sstevel@tonic-gate gettext("\nScanning system physical "
2520Sstevel@tonic-gate "device configuration...\n"));
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /* initialize layout_device_cache */
2550Sstevel@tonic-gate ((error = create_device_caches()) != 0) ||
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate (error = generate_known_disks(&_known_disks, &_bad_disks)) ||
2580Sstevel@tonic-gate (error = generate_known_slices(_known_disks, &_known_slices,
2590Sstevel@tonic-gate &_bad_slices)) ||
2600Sstevel@tonic-gate (error = generate_known_hbas(_known_disks, &_known_hbas));
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate if (error == 0) {
2630Sstevel@tonic-gate print_known_devices();
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate return (error);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate * FUNCTION: release_known_devices()
2710Sstevel@tonic-gate *
2720Sstevel@tonic-gate * RETURNS: int - 0 on success
2730Sstevel@tonic-gate * !0 otherwise
2740Sstevel@tonic-gate *
2750Sstevel@tonic-gate * PURPOSE: Unloads all state currently held for known
2760Sstevel@tonic-gate * physical devices.
2770Sstevel@tonic-gate */
2780Sstevel@tonic-gate int
release_known_devices(char * diskset)2790Sstevel@tonic-gate release_known_devices(
2800Sstevel@tonic-gate char *diskset)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate /* these lists are module private */
2830Sstevel@tonic-gate dlist_free_items(_bad_slices, NULL);
2840Sstevel@tonic-gate dlist_free_items(_bad_disks, NULL);
2850Sstevel@tonic-gate dlist_free_items(_known_slices, NULL);
2860Sstevel@tonic-gate dlist_free_items(_known_disks, NULL);
2870Sstevel@tonic-gate dlist_free_items(_known_hbas, NULL);
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate _bad_slices = NULL;
2900Sstevel@tonic-gate _bad_disks = NULL;
2910Sstevel@tonic-gate _known_slices = NULL;
2920Sstevel@tonic-gate _known_disks = NULL;
2930Sstevel@tonic-gate _known_hbas = NULL;
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate /* clean up state kept in layout_device_cache */
2960Sstevel@tonic-gate release_device_caches();
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate return (0);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate /*
3020Sstevel@tonic-gate * FUNCTION: discover_usable_devices(char *diskset)
3030Sstevel@tonic-gate *
3040Sstevel@tonic-gate * INPUT: diskset - a char * diskset name.
3050Sstevel@tonic-gate *
3060Sstevel@tonic-gate * SIDEEFFECT: Traverses the lists of known devices and populates the
3070Sstevel@tonic-gate * module private lists of usable devices (_usable_slices,
3080Sstevel@tonic-gate * _usable_disks, _usable_hbas), as well as the module
3090Sstevel@tonic-gate * private list of used slices.
3100Sstevel@tonic-gate *
3110Sstevel@tonic-gate * RETURNS: int - 0 on success
3120Sstevel@tonic-gate * !0 otherwise
3130Sstevel@tonic-gate *
3140Sstevel@tonic-gate * PURPOSE: Process the known devices and determine which of them are
3150Sstevel@tonic-gate * usable for generating volumes in the specified diskset.
3160Sstevel@tonic-gate *
3170Sstevel@tonic-gate * The specified diskset's name cannot be NULL or 0 length.
3180Sstevel@tonic-gate */
3190Sstevel@tonic-gate int
discover_usable_devices(char * diskset)3200Sstevel@tonic-gate discover_usable_devices(
3210Sstevel@tonic-gate char *diskset)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate int error = 0;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate dlist_t *used_classes = NULL;
3260Sstevel@tonic-gate dlist_t *iter = NULL;
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if (diskset == NULL || diskset[0] == '\0') {
3290Sstevel@tonic-gate volume_set_error(
3300Sstevel@tonic-gate gettext("a diskset name must be specified in "
3310Sstevel@tonic-gate "the request\n"));
3320Sstevel@tonic-gate return (-1);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
3360Sstevel@tonic-gate gettext("\nDetermining usable physical devices "
3370Sstevel@tonic-gate "for disk set \"%s\"...\n"),
3380Sstevel@tonic-gate diskset);
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate error = generate_usable_disks_and_slices_in_local_set(
3410Sstevel@tonic-gate &used_classes, &_bad_slices, &_usable_disks, &_usable_slices);
3420Sstevel@tonic-gate if (error == 0) {
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate error = generate_usable_disks_and_slices_in_named_set(
3450Sstevel@tonic-gate diskset, &used_classes, &_bad_slices, &_usable_disks,
3460Sstevel@tonic-gate &_usable_slices);
3470Sstevel@tonic-gate if (error == 0) {
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate error = generate_usable_hbas(_usable_disks, &_usable_hbas);
3500Sstevel@tonic-gate if (error == 0) {
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate print_usable_devices();
3530Sstevel@tonic-gate print_unusable_devices(
3540Sstevel@tonic-gate _bad_slices, _bad_disks, used_classes);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /*
3600Sstevel@tonic-gate * free slice classification usage and lists, items are char*
3610Sstevel@tonic-gate * the used_classes structure is only filled in if verbose
3620Sstevel@tonic-gate * output was requested.
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate for (iter = used_classes; iter != NULL; iter = iter->next) {
3650Sstevel@tonic-gate slice_class_t *class = (slice_class_t *)iter->obj;
3660Sstevel@tonic-gate free(class->usage);
3670Sstevel@tonic-gate dlist_free_items(class->sliceinfo, free);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate dlist_free_items(used_classes, free);
3710Sstevel@tonic-gate return (error);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate * FUNCTION: release_usable_devices()
3760Sstevel@tonic-gate *
3770Sstevel@tonic-gate * RETURNS: int - 0 on success
3780Sstevel@tonic-gate * !0 otherwise
3790Sstevel@tonic-gate *
3800Sstevel@tonic-gate * PURPOSE: Unloads all state currently held for usable
3810Sstevel@tonic-gate * physical devices.
3820Sstevel@tonic-gate */
3830Sstevel@tonic-gate int
release_usable_devices()3840Sstevel@tonic-gate release_usable_devices()
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate /* list items are shared with _known_XXX lists */
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate dlist_free_items(_usable_slices, NULL);
3890Sstevel@tonic-gate dlist_free_items(_usable_disks, NULL);
3900Sstevel@tonic-gate dlist_free_items(_usable_hbas, NULL);
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate _usable_slices = NULL;
3930Sstevel@tonic-gate _usable_disks = NULL;
3940Sstevel@tonic-gate _usable_hbas = NULL;
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate /* clean up state kept in layout_device_util */
3970Sstevel@tonic-gate release_virtual_slices();
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate return (0);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * FUNCTION: get_known_slices(dlist_t **list)
4040Sstevel@tonic-gate * get_known_disks(dlist_t **list)
4050Sstevel@tonic-gate * get_known_hbas(dlist_t **list)
4060Sstevel@tonic-gate *
4070Sstevel@tonic-gate * OUTPUT: list - a dlist_t pointer to hold the returned list of
4080Sstevel@tonic-gate * devices.
4090Sstevel@tonic-gate *
4100Sstevel@tonic-gate * RETURNS: int - 0 on success
4110Sstevel@tonic-gate * !0 otherwise
4120Sstevel@tonic-gate *
4130Sstevel@tonic-gate * PURPOSE: Public accessors for the module private lists of
4140Sstevel@tonic-gate * available devices.
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate int
get_known_slices(dlist_t ** list)4170Sstevel@tonic-gate get_known_slices(
4180Sstevel@tonic-gate dlist_t **list)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate *list = _known_slices;
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate return (0);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate int
get_known_disks(dlist_t ** list)4260Sstevel@tonic-gate get_known_disks(
4270Sstevel@tonic-gate dlist_t **list)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate *list = _known_disks;
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate return (0);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate int
get_known_hbas(dlist_t ** list)4350Sstevel@tonic-gate get_known_hbas(
4360Sstevel@tonic-gate dlist_t **list)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate *list = _known_hbas;
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate return (0);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate /* make fully qualified DID device name */
4440Sstevel@tonic-gate static char *
make_fully_qualified_did_device_name(char * device)4450Sstevel@tonic-gate make_fully_qualified_did_device_name(
4460Sstevel@tonic-gate char *device)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate static char buf[MAXPATHLEN];
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate if (device != NULL && strrchr(device, '/') == NULL) {
4510Sstevel@tonic-gate (void) snprintf(buf, MAXPATHLEN-1, "%s/%s",
4520Sstevel@tonic-gate "/dev/did/dsk", device);
4530Sstevel@tonic-gate return (buf);
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate return (device);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate /*
4600Sstevel@tonic-gate * FUNCTION: generate_known_disks(dlist_t **known,
4610Sstevel@tonic-gate * dlist_t **bad)
4620Sstevel@tonic-gate *
4630Sstevel@tonic-gate * INPUT: NONE
4640Sstevel@tonic-gate *
4650Sstevel@tonic-gate * OUTPUT: known - populated list of known disks
4660Sstevel@tonic-gate * bad - populated list of known bad disks
4670Sstevel@tonic-gate *
4680Sstevel@tonic-gate * RETURNS: int - 0 on success
4690Sstevel@tonic-gate * !0 otherwise
4700Sstevel@tonic-gate *
4710Sstevel@tonic-gate * PURPOSE: Does the system configuration discovery to determine
4720Sstevel@tonic-gate * what disks are known to be attached to the system.
4730Sstevel@tonic-gate *
4740Sstevel@tonic-gate * Determines the CTD name for each disk and saves it.
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate static int
generate_known_disks(dlist_t ** known,dlist_t ** bad)4770Sstevel@tonic-gate generate_known_disks(
4780Sstevel@tonic-gate dlist_t **known,
4790Sstevel@tonic-gate dlist_t **bad)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate int i;
4820Sstevel@tonic-gate int error = 0;
4830Sstevel@tonic-gate dm_descriptor_t *ddp;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate ddp = dm_get_descriptors(DM_DRIVE, NULL, &error);
4860Sstevel@tonic-gate (void) add_descriptors_to_free(ddp);
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate *known = NULL;
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate if (error != 0) {
4910Sstevel@tonic-gate volume_set_error(
4920Sstevel@tonic-gate gettext("Error discovering system hardware configuration,\n"
4930Sstevel@tonic-gate "unable to communicate with libdiskmgt or diskmgtd.\n"));
4940Sstevel@tonic-gate return (-1);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate if ((ddp == NULL) || (ddp[0] == NULL)) {
4980Sstevel@tonic-gate volume_set_error(gettext("there are no known disks\n"));
4990Sstevel@tonic-gate return (-1);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /* iterate all returned disks and add them to the known list */
5030Sstevel@tonic-gate for (i = 0; (ddp[i] != NULL) && (error == 0); i++) {
5040Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)ddp[i];
5050Sstevel@tonic-gate dlist_t *aliases = NULL;
5060Sstevel@tonic-gate uint32_t mtype = DM_MT_UNKNOWN;
5070Sstevel@tonic-gate uint32_t dtype = DM_DT_UNKNOWN;
5080Sstevel@tonic-gate boolean_t bad_disk = B_FALSE;
5090Sstevel@tonic-gate boolean_t online = B_TRUE;
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate #if defined(i386)
5120Sstevel@tonic-gate /* on X86, disks must have a solaris FDISK partition */
5130Sstevel@tonic-gate boolean_t solpart = B_FALSE;
5140Sstevel@tonic-gate #endif /* defined(i386) */
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate if (((error = disk_get_is_online(disk, &online)) == 0 &&
5170Sstevel@tonic-gate online == B_FALSE) || error == ENODEV) {
5180Sstevel@tonic-gate /* if the disk is offline, report it as bad */
5190Sstevel@tonic-gate bad_disk = B_TRUE;
5200Sstevel@tonic-gate error = 0;
5210Sstevel@tonic-gate } else
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate if (error == 0 &&
5240Sstevel@tonic-gate (((error = disk_get_media_type(disk, &mtype)) != 0) ||
5250Sstevel@tonic-gate ((error = disk_get_drive_type(disk, &dtype)) != 0)) &&
5260Sstevel@tonic-gate error == ENODEV) {
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate * if any disk attribute access fails with ENODEV
5290Sstevel@tonic-gate * report it as bad
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate bad_disk = B_TRUE;
5320Sstevel@tonic-gate error = 0;
5330Sstevel@tonic-gate } else {
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /*
5360Sstevel@tonic-gate * Determine whether disk is fixed by checking its
5370Sstevel@tonic-gate * drive type. If drive type is unknown, check media
5380Sstevel@tonic-gate * type.
5390Sstevel@tonic-gate */
5400Sstevel@tonic-gate int isfixed = (dtype == DM_DT_FIXED ||
5410Sstevel@tonic-gate (dtype == DM_DT_UNKNOWN && mtype == DM_MT_FIXED));
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate if (!isfixed) {
5440Sstevel@tonic-gate continue; /* ignore non-fixed disks */
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate #if defined(i386)
5480Sstevel@tonic-gate if (((error = disk_get_has_solaris_partition(disk,
5490Sstevel@tonic-gate &solpart)) != 0) || (solpart != B_TRUE)) {
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate /* X86 drive has no solaris partition, report as bad */
5520Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
5530Sstevel@tonic-gate gettext("%s has no solaris FDISK partition.\n"));
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate bad_disk = B_TRUE;
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate #endif /* defined(i386) */
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate if (bad_disk) {
5620Sstevel@tonic-gate /* remember bad disks and continue */
563*62Sjeanm if (dlist_contains(*bad, (void *)(uintptr_t)disk,
564*62Sjeanm compare_descriptor_names) != B_TRUE) {
565*62Sjeanm dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
5660Sstevel@tonic-gate if (item == NULL) {
5670Sstevel@tonic-gate error = ENOMEM;
5680Sstevel@tonic-gate } else {
5690Sstevel@tonic-gate *bad = dlist_append(item, *bad, AT_TAIL);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate continue;
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate /* get disk name and multipath aliases */
5760Sstevel@tonic-gate if ((error = disk_get_aliases(disk, &aliases)) == 0) {
5770Sstevel@tonic-gate dlist_t *iter;
5780Sstevel@tonic-gate boolean_t disk_name_set = B_FALSE;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate for (iter = aliases;
5810Sstevel@tonic-gate (iter != NULL) && (error == 0);
5820Sstevel@tonic-gate iter = iter->next) {
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate dm_descriptor_t ap = (uintptr_t)iter->obj;
5850Sstevel@tonic-gate char *alias;
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate if ((error = get_name(ap, &alias)) == 0) {
5880Sstevel@tonic-gate /* save first alias as display name */
5890Sstevel@tonic-gate if (disk_name_set != B_TRUE) {
5900Sstevel@tonic-gate /* make sure DID disk alias is fully qualified */
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate if (is_did_disk_name(alias) == B_TRUE) {
5930Sstevel@tonic-gate char *qual_name =
5940Sstevel@tonic-gate make_fully_qualified_did_device_name(alias);
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate set_display_name(disk, qual_name);
5970Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
5980Sstevel@tonic-gate gettext("DID disk name: %s\n"),
5990Sstevel@tonic-gate qual_name);
6000Sstevel@tonic-gate } else {
6010Sstevel@tonic-gate set_display_name(disk, alias);
6020Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
6030Sstevel@tonic-gate gettext("disk name: %s\n"),
6040Sstevel@tonic-gate alias);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate disk_name_set = B_TRUE;
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate } else {
6090Sstevel@tonic-gate /* save others as aliases */
6100Sstevel@tonic-gate set_alias(disk, alias);
6110Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
6120Sstevel@tonic-gate gettext(" alias: %s\n"),
6130Sstevel@tonic-gate alias);
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate dlist_free_items(aliases, NULL);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate if (error == 0) {
622*62Sjeanm dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
6230Sstevel@tonic-gate if (item == NULL) {
6240Sstevel@tonic-gate error = ENOMEM;
6250Sstevel@tonic-gate } else {
6260Sstevel@tonic-gate *known =
6270Sstevel@tonic-gate dlist_insert_ordered(item, *known,
6280Sstevel@tonic-gate ASCENDING, compare_desc_display_names);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate if (ddp != NULL) {
6340Sstevel@tonic-gate free(ddp);
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate return (error);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate * FUNCTION: generate_known_slices(dlist_t *disks,
6420Sstevel@tonic-gate * dlist_t **known, dlist_t **bad)
6430Sstevel@tonic-gate *
6440Sstevel@tonic-gate * OUTPUT: disks - a pointer to a list of known disks
6450Sstevel@tonic-gate * known - a pointer to a dlist_t list to hold the known slices
6460Sstevel@tonic-gate * bad - a pointer to a dlist_t to hold the bad slices
6470Sstevel@tonic-gate *
6480Sstevel@tonic-gate * RETURNS: int - 0 on success
6490Sstevel@tonic-gate * !0 otherwise.
6500Sstevel@tonic-gate *
6510Sstevel@tonic-gate * PURPOSE: Examines input list of known disks and determines the slices
6520Sstevel@tonic-gate * attached to each.
6530Sstevel@tonic-gate *
6540Sstevel@tonic-gate * Some slices returned from libdiskmgt may not really exist,
6550Sstevel@tonic-gate * this is detected when trying to get more information about
6560Sstevel@tonic-gate * the slice -- ENODEV is returned. Any such slices will be
6570Sstevel@tonic-gate * added to the bad slice list.
6580Sstevel@tonic-gate */
6590Sstevel@tonic-gate static int
generate_known_slices(dlist_t * disks,dlist_t ** known,dlist_t ** bad)6600Sstevel@tonic-gate generate_known_slices(
6610Sstevel@tonic-gate dlist_t *disks,
6620Sstevel@tonic-gate dlist_t **known,
6630Sstevel@tonic-gate dlist_t **bad)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate dlist_t *iter;
6660Sstevel@tonic-gate int error = 0;
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate /* iterate list of disks and add their slices to the known list */
6690Sstevel@tonic-gate for (iter = disks; (iter != NULL) && (error == 0); iter = iter->next) {
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj;
6720Sstevel@tonic-gate dlist_t *slices = NULL;
6730Sstevel@tonic-gate dlist_t *iter1;
6740Sstevel@tonic-gate char *dname = NULL;
6750Sstevel@tonic-gate boolean_t disk_ctd_alias_derived = B_FALSE;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate if (((error = disk_get_slices(disk, &slices)) != 0) ||
6780Sstevel@tonic-gate ((error = get_display_name(disk, &dname)) != 0)) {
6790Sstevel@tonic-gate continue;
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate for (iter1 = slices;
6830Sstevel@tonic-gate (iter1 != NULL) && (error == 0);
6840Sstevel@tonic-gate iter1 = iter1->next) {
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate dm_descriptor_t slice = (uintptr_t)iter1->obj;
6870Sstevel@tonic-gate uint32_t index = 0;
6880Sstevel@tonic-gate nvlist_t *attrs = NULL;
6890Sstevel@tonic-gate char *sname = NULL;
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate if (((error = get_name(slice, &sname)) != 0) ||
6920Sstevel@tonic-gate ((error = slice_get_index(slice, &index)) != 0) ||
6930Sstevel@tonic-gate ((error = get_cached_attributes(slice, &attrs)) != 0)) {
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate if (error == ENODEV) {
6960Sstevel@tonic-gate /* bad slice, remember it and continue */
697*62Sjeanm dlist_t *item =
698*62Sjeanm dlist_new_item((void *)(uintptr_t)slice);
6990Sstevel@tonic-gate if (item == NULL) {
7000Sstevel@tonic-gate error = ENOMEM;
7010Sstevel@tonic-gate } else {
7020Sstevel@tonic-gate *bad = dlist_insert_ordered(
7030Sstevel@tonic-gate item, *bad,
7040Sstevel@tonic-gate ASCENDING, compare_descriptor_names);
7050Sstevel@tonic-gate error = 0;
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate continue;
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate if ((error == 0) && (is_did_slice_name(sname) == B_TRUE) &&
7120Sstevel@tonic-gate (disk_ctd_alias_derived == B_FALSE)) {
7130Sstevel@tonic-gate /* BEGIN CSTYLED */
7140Sstevel@tonic-gate /*
7150Sstevel@tonic-gate * If the slice name is a DID name, get the local CTD
7160Sstevel@tonic-gate * name for slice, extract the disk name and add it as
7170Sstevel@tonic-gate * an alias for the disk.
7180Sstevel@tonic-gate *
7190Sstevel@tonic-gate * This is the only way to derive the CTD alias for the
7200Sstevel@tonic-gate * disk when DID is enabled.
7210Sstevel@tonic-gate *
7220Sstevel@tonic-gate * The disk_ctd_alias_derived flag ensure the disk's
7230Sstevel@tonic-gate * CTD alias is only set once.
7240Sstevel@tonic-gate *
7250Sstevel@tonic-gate * The slice's CTD aliases are then derived from the
7260Sstevel@tonic-gate * disk's CTD alias in the normal, non-DID name processing
7270Sstevel@tonic-gate * which happens below.
7280Sstevel@tonic-gate */
7290Sstevel@tonic-gate /* END CSTYLED */
7300Sstevel@tonic-gate char *local = NULL;
7310Sstevel@tonic-gate if ((error = nvlist_lookup_string(attrs, DM_LOCALNAME,
7320Sstevel@tonic-gate &local)) != 0) {
7330Sstevel@tonic-gate if (error == ENOENT) {
7340Sstevel@tonic-gate /* no local name -> no DID */
7350Sstevel@tonic-gate error = 0;
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate } else {
7380Sstevel@tonic-gate char *localdisk = NULL;
7390Sstevel@tonic-gate char *diskonly = NULL;
7400Sstevel@tonic-gate if ((error = extract_diskname(local,
7410Sstevel@tonic-gate &localdisk)) == 0) {
7420Sstevel@tonic-gate if ((diskonly = strrchr(localdisk, '/')) != NULL) {
7430Sstevel@tonic-gate ++diskonly;
7440Sstevel@tonic-gate } else {
7450Sstevel@tonic-gate diskonly = localdisk;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
7480Sstevel@tonic-gate gettext(" set DID disk CTD alias: %s\n"),
7490Sstevel@tonic-gate diskonly);
7500Sstevel@tonic-gate error = set_alias(disk, diskonly);
7510Sstevel@tonic-gate free(localdisk);
7520Sstevel@tonic-gate disk_ctd_alias_derived = B_TRUE;
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate /* derive slice display name from disk's display name */
7580Sstevel@tonic-gate if (error == 0) {
7590Sstevel@tonic-gate if ((error = make_slicename_for_diskname_and_index(
7600Sstevel@tonic-gate dname, index, &sname)) == 0) {
7610Sstevel@tonic-gate error = set_display_name(slice, sname);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate /* set slice aliases using disk aliases */
7660Sstevel@tonic-gate if (error == 0) {
7670Sstevel@tonic-gate dlist_t *aliases = NULL;
7680Sstevel@tonic-gate if ((error = get_aliases(disk, &aliases)) == 0) {
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate dlist_t *iter2 = aliases;
7710Sstevel@tonic-gate for (; (iter2 != NULL) && (error == 0);
7720Sstevel@tonic-gate iter2 = iter2->next) {
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate char *dalias = (char *)iter2->obj;
7750Sstevel@tonic-gate char *salias = NULL;
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate if ((error = make_slicename_for_diskname_and_index(
7780Sstevel@tonic-gate dalias, index, &salias)) == 0) {
7790Sstevel@tonic-gate error = set_alias(slice, salias);
7800Sstevel@tonic-gate free(salias);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate dlist_free_items(aliases, free);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate if (error == 0) {
788*62Sjeanm dlist_t *item = dlist_new_item((void *)(uintptr_t)slice);
7890Sstevel@tonic-gate if (item == NULL) {
7900Sstevel@tonic-gate error = ENOMEM;
7910Sstevel@tonic-gate } else {
7920Sstevel@tonic-gate *known =
7930Sstevel@tonic-gate dlist_insert_ordered(
7940Sstevel@tonic-gate item, *known,
7950Sstevel@tonic-gate ASCENDING, compare_desc_display_names);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate }
7980Sstevel@tonic-gate }
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate dlist_free_items(slices, NULL);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate return (error);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate /*
8070Sstevel@tonic-gate * FUNCTION: generate_known_hbas(dlist_t *disks, dlist_t **known)
8080Sstevel@tonic-gate *
8090Sstevel@tonic-gate * INPUT: diskset - a char * diskset name.
8100Sstevel@tonic-gate *
8110Sstevel@tonic-gate * OUTPUT: populates the list of known HBAs.
8120Sstevel@tonic-gate *
8130Sstevel@tonic-gate * RETURNS: int - 0 on success
8140Sstevel@tonic-gate * !0 otherwise
8150Sstevel@tonic-gate *
8160Sstevel@tonic-gate * PURPOSE: Examines known disk list and derives the list of known HBAs.
8170Sstevel@tonic-gate *
8180Sstevel@tonic-gate * Determines the CTD name for an HBA and saves it.
8190Sstevel@tonic-gate */
8200Sstevel@tonic-gate static int
generate_known_hbas(dlist_t * disks,dlist_t ** known)8210Sstevel@tonic-gate generate_known_hbas(
8220Sstevel@tonic-gate dlist_t *disks,
8230Sstevel@tonic-gate dlist_t **known)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate dlist_t *iter;
8260Sstevel@tonic-gate int error = 0;
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate /*
8290Sstevel@tonic-gate * for each known disk follow its HBA connections and
8300Sstevel@tonic-gate * assemble the list of known HBAs.
8310Sstevel@tonic-gate */
8320Sstevel@tonic-gate for (iter = disks;
8330Sstevel@tonic-gate (iter != NULL) && (error == 0);
8340Sstevel@tonic-gate iter = iter->next) {
8350Sstevel@tonic-gate
8360Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj;
8370Sstevel@tonic-gate dlist_t *hbas = NULL;
8380Sstevel@tonic-gate dlist_t *iter2 = NULL;
8390Sstevel@tonic-gate dlist_t *iter3 = NULL;
8400Sstevel@tonic-gate dlist_t *aliases = NULL;
8410Sstevel@tonic-gate char *dname = NULL;
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate ((error = get_display_name(disk, &dname)) != 0) ||
8440Sstevel@tonic-gate (error = disk_get_aliases(disk, &aliases)) ||
8450Sstevel@tonic-gate (error = disk_get_hbas(disk, &hbas));
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate if (error == 0) {
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate if ((hbas == NULL) || (dlist_length(hbas) == 0)) {
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
8520Sstevel@tonic-gate gettext("Disk %s has no HBA/Controller?!\n"),
8530Sstevel@tonic-gate dname);
8540Sstevel@tonic-gate error = -1;
8550Sstevel@tonic-gate
8560Sstevel@tonic-gate dlist_free_items(hbas, NULL);
8570Sstevel@tonic-gate dlist_free_items(aliases, NULL);
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate continue;
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate for (iter2 = hbas, iter3 = aliases;
8630Sstevel@tonic-gate iter2 != NULL && iter3 != NULL;
8640Sstevel@tonic-gate iter2 = iter2->next, iter3 = iter3->next) {
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate dm_descriptor_t hba = (uintptr_t)iter2->obj;
8670Sstevel@tonic-gate dm_descriptor_t alias = (uintptr_t)iter3->obj;
8680Sstevel@tonic-gate dlist_t *item = NULL;
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate /* scan list of known HBAs and see if known */
871*62Sjeanm if (dlist_contains(*known, (void*)(uintptr_t)hba,
872*62Sjeanm compare_descriptor_names) == B_TRUE) {
8730Sstevel@tonic-gate /* known HBA */
8740Sstevel@tonic-gate continue;
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate /* see if HBA supports MPXIO */
8780Sstevel@tonic-gate if ((error == 0) && (_mpxio_enabled != B_TRUE)) {
8790Sstevel@tonic-gate hba_is_multiplex(hba, &_mpxio_enabled);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate /* generate a CTD name for HBA */
8830Sstevel@tonic-gate error = generate_known_hba_name(hba, alias, disk);
8840Sstevel@tonic-gate if (error == 0) {
8850Sstevel@tonic-gate /* add to known HBA list */
886*62Sjeanm if ((item = dlist_new_item((void *)(uintptr_t)hba)) ==
887*62Sjeanm NULL) {
8880Sstevel@tonic-gate error = ENOMEM;
8890Sstevel@tonic-gate } else {
8900Sstevel@tonic-gate *known =
8910Sstevel@tonic-gate dlist_insert_ordered(item, *known,
8920Sstevel@tonic-gate ASCENDING, compare_desc_display_names);
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate dlist_free_items(aliases, NULL);
8990Sstevel@tonic-gate dlist_free_items(hbas, NULL);
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate return (error);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate * FUNCTION: generate_known_hba_name(dm_descriptor_t hba,
9070Sstevel@tonic-gate * dm_descriptor_t alias, char *diskname)
9080Sstevel@tonic-gate *
9090Sstevel@tonic-gate * INPUT: hba - a dm_descriptor_t HBA handle.
9100Sstevel@tonic-gate * alias - a dm_descriptor_t disk alias handle.
9110Sstevel@tonic-gate * diskname - a char * disk name
9120Sstevel@tonic-gate *
9130Sstevel@tonic-gate * RETURNS: int - 0 on success
9140Sstevel@tonic-gate * !0 otherwise
9150Sstevel@tonic-gate *
9160Sstevel@tonic-gate * PURPOSE: Sets the CTD name for the input HBA.
9170Sstevel@tonic-gate *
9180Sstevel@tonic-gate * The CTD name for the HBA is generated from the input
9190Sstevel@tonic-gate * disk alias (ex: cXdXtXsX) or from the disk name if
9200Sstevel@tonic-gate * the input alias is a DID name (ex: dX).
9210Sstevel@tonic-gate */
9220Sstevel@tonic-gate static int
generate_known_hba_name(dm_descriptor_t hba,dm_descriptor_t alias,dm_descriptor_t disk)9230Sstevel@tonic-gate generate_known_hba_name(
9240Sstevel@tonic-gate dm_descriptor_t hba,
9250Sstevel@tonic-gate dm_descriptor_t alias,
9260Sstevel@tonic-gate dm_descriptor_t disk)
9270Sstevel@tonic-gate {
9280Sstevel@tonic-gate char *hbaname = NULL;
9290Sstevel@tonic-gate char *aliasname = NULL;
9300Sstevel@tonic-gate int error = 0;
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate ((error = get_name(alias, &aliasname)) != 0) ||
9330Sstevel@tonic-gate (error = extract_hbaname(aliasname, &hbaname));
9340Sstevel@tonic-gate if (error != 0) {
9350Sstevel@tonic-gate free(hbaname);
9360Sstevel@tonic-gate return (error);
9370Sstevel@tonic-gate }
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate /* see if the input alias is a DID name... */
9400Sstevel@tonic-gate if (is_did_disk_name(aliasname) == B_TRUE) {
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate /* look for a non-DID name in disk's aliases */
9430Sstevel@tonic-gate dlist_t *aliases = NULL;
9440Sstevel@tonic-gate error = get_aliases(disk, &aliases);
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate for (; (error == 0) && (aliases != NULL);
9470Sstevel@tonic-gate aliases = aliases->next) {
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate aliasname = (char *)aliases->obj;
9500Sstevel@tonic-gate if (is_did_disk_name(aliasname) != B_TRUE) {
9510Sstevel@tonic-gate /* this is the "local" CTD name generated by */
9520Sstevel@tonic-gate /* generate_known_disks() above */
9530Sstevel@tonic-gate error = extract_hbaname(aliasname, &hbaname);
9540Sstevel@tonic-gate if ((error == 0) && (hbaname != NULL)) {
9550Sstevel@tonic-gate set_display_name(hba, hbaname);
9560Sstevel@tonic-gate break;
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate dlist_free_items(aliases, free);
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate } else {
9630Sstevel@tonic-gate /* use whatever was derived from the alias name */
9640Sstevel@tonic-gate set_display_name(hba, hbaname);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate return (error);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate * FUNCTION: print_known_devices()
9720Sstevel@tonic-gate *
9730Sstevel@tonic-gate * PURPOSE: Print out the known devices.
9740Sstevel@tonic-gate *
9750Sstevel@tonic-gate * Iterates the lists of known slices, disks and HBAs
9760Sstevel@tonic-gate * and prints out their CTD and device names.
9770Sstevel@tonic-gate */
9780Sstevel@tonic-gate static void
print_known_devices(char * diskset)9790Sstevel@tonic-gate print_known_devices(
9800Sstevel@tonic-gate char *diskset)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate int i = 0;
9830Sstevel@tonic-gate struct {
9840Sstevel@tonic-gate char *msg;
9850Sstevel@tonic-gate dlist_t *list;
9860Sstevel@tonic-gate } devs[3];
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate devs[0].msg = gettext("HBA/Controllers");
9890Sstevel@tonic-gate devs[0].list = _known_hbas;
9900Sstevel@tonic-gate devs[1].msg = gettext("disks");
9910Sstevel@tonic-gate devs[1].list = _known_disks;
9920Sstevel@tonic-gate devs[2].msg = gettext("slices");
9930Sstevel@tonic-gate devs[2].list = _known_slices;
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate for (i = 0; i < 3; i++) {
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
9980Sstevel@tonic-gate gettext("\n These %s are known:\n\n"),
9990Sstevel@tonic-gate devs[i].msg);
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate print_device_list(devs[i].list);
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate /*
10060Sstevel@tonic-gate * FUNCTION: get_usable_slices(dlist_t **list)
10070Sstevel@tonic-gate *
10080Sstevel@tonic-gate * OUTPUT: list - a dlist_t pointer to hold the returned list of
10090Sstevel@tonic-gate * devices.
10100Sstevel@tonic-gate *
10110Sstevel@tonic-gate * RETURNS: int - 0 on success
10120Sstevel@tonic-gate * !0 otherwise
10130Sstevel@tonic-gate *
10140Sstevel@tonic-gate * PURPOSE: Public accessors the the modules private lists of
10150Sstevel@tonic-gate * available devices.
10160Sstevel@tonic-gate *
10170Sstevel@tonic-gate * The functions are keyed by diskset name in the event
10180Sstevel@tonic-gate * objects in different disksets are loaded concurrently.
10190Sstevel@tonic-gate */
10200Sstevel@tonic-gate int
get_usable_slices(dlist_t ** list)10210Sstevel@tonic-gate get_usable_slices(
10220Sstevel@tonic-gate dlist_t **list)
10230Sstevel@tonic-gate {
10240Sstevel@tonic-gate *list = _usable_slices;
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate return (0);
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate int
get_usable_disks(dlist_t ** list)10300Sstevel@tonic-gate get_usable_disks(
10310Sstevel@tonic-gate dlist_t **list)
10320Sstevel@tonic-gate {
10330Sstevel@tonic-gate *list = _usable_disks;
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate return (0);
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate int
get_usable_hbas(dlist_t ** list)10390Sstevel@tonic-gate get_usable_hbas(
10400Sstevel@tonic-gate dlist_t **list)
10410Sstevel@tonic-gate {
10420Sstevel@tonic-gate *list = _usable_hbas;
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate return (0);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate
10470Sstevel@tonic-gate /*
10480Sstevel@tonic-gate * FUNCTION: generate_usable_disks_and_slices_in_local_set(dlist_t **classes,
10490Sstevel@tonic-gate * dlist_t **bad_disks, dlist_t **usable_disks,
10500Sstevel@tonic-gate * dlist_t **usable_slices)
10510Sstevel@tonic-gate *
10520Sstevel@tonic-gate * OUTPUT: used_classes - a pointer to a list of slice_class_t structs
10530Sstevel@tonic-gate * updated with known slices that have detected uses
10540Sstevel@tonic-gate * added to the correct class'e list of slices.
10550Sstevel@tonic-gate * bad_disks - a pointer to a list of bad/unusable disks updated
10560Sstevel@tonic-gate * with any bad disks that were detected
10570Sstevel@tonic-gate * useable_disks - a pointer to a list of usable disks
10580Sstevel@tonic-gate * useable_slices - a pointer to a list of usable slices
10590Sstevel@tonic-gate *
10600Sstevel@tonic-gate * RETURNS: int - 0 on success
10610Sstevel@tonic-gate * !0 otherwise.
10620Sstevel@tonic-gate *
10630Sstevel@tonic-gate * PURPOSE: Scans the disks in the local set to determine which are
10640Sstevel@tonic-gate * usable during layout processing.
10650Sstevel@tonic-gate *
10660Sstevel@tonic-gate * Determines which are usable by layout using usages detected
10670Sstevel@tonic-gate * by libdiskmgt.
10680Sstevel@tonic-gate */
10690Sstevel@tonic-gate static int
generate_usable_disks_and_slices_in_local_set(dlist_t ** classes,dlist_t ** bad_slices,dlist_t ** usable_disks,dlist_t ** usable_slices)10700Sstevel@tonic-gate generate_usable_disks_and_slices_in_local_set(
10710Sstevel@tonic-gate dlist_t **classes,
10720Sstevel@tonic-gate dlist_t **bad_slices,
10730Sstevel@tonic-gate dlist_t **usable_disks,
10740Sstevel@tonic-gate dlist_t **usable_slices)
10750Sstevel@tonic-gate {
10760Sstevel@tonic-gate char *dsname = MD_LOCAL_NAME;
10770Sstevel@tonic-gate dlist_t *disks;
10780Sstevel@tonic-gate dlist_t *iter;
10790Sstevel@tonic-gate int error;
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate /* Get disks in local set */
10820Sstevel@tonic-gate error = get_disks_in_diskset(dsname, &disks);
10830Sstevel@tonic-gate if (error != 0) {
10840Sstevel@tonic-gate return (error);
10850Sstevel@tonic-gate }
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate /* For each disk in this set... */
10880Sstevel@tonic-gate for (iter = disks; iter != NULL && error == 0; iter = iter->next) {
10890Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj;
10900Sstevel@tonic-gate dlist_t *slices;
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate /* Get slices on this disk */
10930Sstevel@tonic-gate error = disk_get_slices(disk, &slices);
10940Sstevel@tonic-gate if (error == 0) {
10950Sstevel@tonic-gate dlist_t *iter2;
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate /*
10980Sstevel@tonic-gate * Assume disk is available until a bad or unavailable
10990Sstevel@tonic-gate * slice is found
11000Sstevel@tonic-gate */
11010Sstevel@tonic-gate boolean_t avail = B_TRUE;
11020Sstevel@tonic-gate boolean_t bad_disk = B_FALSE;
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate /* For each slice on this disk... */
11050Sstevel@tonic-gate for (iter2 = slices;
11060Sstevel@tonic-gate iter2 != NULL && error == 0 &&
11070Sstevel@tonic-gate avail == B_TRUE && bad_disk == B_FALSE;
11080Sstevel@tonic-gate iter2 = iter2->next) {
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate dm_descriptor_t slice = (uintptr_t)iter2->obj;
11110Sstevel@tonic-gate dlist_t *bad_slices_on_this_disk = NULL;
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate /* Is this slice available? */
11140Sstevel@tonic-gate error = check_slice_usage(dsname, slice,
11150Sstevel@tonic-gate disk, &avail, &bad_slices_on_this_disk, classes);
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate /* Is the slice bad (inaccessible)? */
11180Sstevel@tonic-gate if (error != 0 && bad_slices_on_this_disk != NULL) {
11190Sstevel@tonic-gate bad_disk = B_TRUE;
11200Sstevel@tonic-gate *bad_slices = dlist_append_list(
11210Sstevel@tonic-gate *bad_slices, bad_slices_on_this_disk);
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate /* Is the disk available? */
11260Sstevel@tonic-gate if (error == 0 && bad_disk == B_FALSE && avail == B_TRUE) {
11270Sstevel@tonic-gate error = dlist_append_object(
1128*62Sjeanm (void *)(uintptr_t)disk, usable_disks, AT_TAIL);
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate dlist_free_items(slices, NULL);
11320Sstevel@tonic-gate }
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate dlist_free_items(disks, NULL);
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate if (error == 0) {
11380Sstevel@tonic-gate /* BEGIN CSTYLED */
11390Sstevel@tonic-gate /*
11400Sstevel@tonic-gate * Now reslice usable disks in the local set to
11410Sstevel@tonic-gate * simulate the slices they'll have when they're added
11420Sstevel@tonic-gate * to the named disk set, and add these resulting
11430Sstevel@tonic-gate * virtual slices to the list of available slices.
11440Sstevel@tonic-gate */
11450Sstevel@tonic-gate /* END CSTYLED */
11460Sstevel@tonic-gate error = generate_virtual_slices(*usable_disks, usable_slices);
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate return (error);
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate
11520Sstevel@tonic-gate /*
11530Sstevel@tonic-gate * FUNCTION: generate_virtual_slices(dlist_t *unused, dlist_t **usable)
11540Sstevel@tonic-gate *
11550Sstevel@tonic-gate * INPUT: slice_classes - a list of unused slice dm_descriptor_t handles.
11560Sstevel@tonic-gate *
11570Sstevel@tonic-gate * OUTPUT: usable - pointer to the list of usable slices, updated
11580Sstevel@tonic-gate * with any created virtual slices.
11590Sstevel@tonic-gate *
11600Sstevel@tonic-gate * RETURNS: int - 0 on success
11610Sstevel@tonic-gate * !0 otherwise.
11620Sstevel@tonic-gate *
11630Sstevel@tonic-gate * PURPOSE: Helper which creates virtual slices for each disk which
11640Sstevel@tonic-gate * could be added to a diskset if necessary...
11650Sstevel@tonic-gate *
11660Sstevel@tonic-gate * Search the input list of slice classes for the entry
11670Sstevel@tonic-gate * containing slices known to be available for use by layout.
11680Sstevel@tonic-gate *
11690Sstevel@tonic-gate * Iterate the list of unused slices and determine the set
11700Sstevel@tonic-gate * of unique disks.
11710Sstevel@tonic-gate *
11720Sstevel@tonic-gate * For each unique disk, create virtual slice descriptors to
11730Sstevel@tonic-gate * represent those that will exist if/when the disk is added
11740Sstevel@tonic-gate * to the diskset.
11750Sstevel@tonic-gate *
11760Sstevel@tonic-gate * Add theese virtual slices to the list of usable slices.
11770Sstevel@tonic-gate */
11780Sstevel@tonic-gate static int
generate_virtual_slices(dlist_t * avail_disks_local_set,dlist_t ** usable)11790Sstevel@tonic-gate generate_virtual_slices(
11800Sstevel@tonic-gate dlist_t *avail_disks_local_set,
11810Sstevel@tonic-gate dlist_t **usable)
11820Sstevel@tonic-gate {
11830Sstevel@tonic-gate dlist_t *iter = NULL;
11840Sstevel@tonic-gate int error = 0;
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate /* generate virtual slices */
11870Sstevel@tonic-gate error = create_virtual_slices(avail_disks_local_set);
11880Sstevel@tonic-gate if (error == 0) {
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate get_virtual_slices(&iter);
11910Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) {
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *) iter->obj);
11940Sstevel@tonic-gate if (item == NULL) {
11950Sstevel@tonic-gate error = ENOMEM;
11960Sstevel@tonic-gate } else {
11970Sstevel@tonic-gate *usable =
11980Sstevel@tonic-gate dlist_insert_ordered(item, *usable,
11990Sstevel@tonic-gate ASCENDING, compare_desc_display_names);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate return (error);
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate
12070Sstevel@tonic-gate /*
12080Sstevel@tonic-gate * FUNCTION: generate_usable_disks_and_slices_in_named_set(char *dsname,
12090Sstevel@tonic-gate * dlist_t **classes, dlist_t **bad_slices,
12100Sstevel@tonic-gate * dlist_t **usable_slices, dlist_t **usable_disks)
12110Sstevel@tonic-gate *
12120Sstevel@tonic-gate * INPUT: dsname - a char * diskset name.
12130Sstevel@tonic-gate *
12140Sstevel@tonic-gate * OUTPUT: classes - pointer to a list of slice_class_t structs,
12150Sstevel@tonic-gate * updated to include slices in the disk set with
12160Sstevel@tonic-gate * known uses.
12170Sstevel@tonic-gate * bad_slices - pointer to a list of bad/unusable slices,
12180Sstevel@tonic-gate * updated to include slices in the disk set that
12190Sstevel@tonic-gate * are inaccessible or no longer existent.
12200Sstevel@tonic-gate * usable_slices - pointer to a list of usable slices in the
12210Sstevel@tonic-gate * disk set.
12220Sstevel@tonic-gate * usable_disks - pointer to a list of usable disks in the
12230Sstevel@tonic-gate * disk set.
12240Sstevel@tonic-gate *
12250Sstevel@tonic-gate * RETURNS: int - 0 on success
12260Sstevel@tonic-gate * !0 otherwise.
12270Sstevel@tonic-gate *
12280Sstevel@tonic-gate * PURPOSE: 1. determine the disks in the named disk set
12290Sstevel@tonic-gate * 2. determine the used slices on the disks
12300Sstevel@tonic-gate * 3. determine the unused slices on the disks
12310Sstevel@tonic-gate * 4. look for unused space on the disks and collect it
12320Sstevel@tonic-gate * into an existing unused slice, or create a new
12330Sstevel@tonic-gate * virtual slice.
12340Sstevel@tonic-gate */
12350Sstevel@tonic-gate static int
generate_usable_disks_and_slices_in_named_set(char * dsname,dlist_t ** classes,dlist_t ** bad_slices,dlist_t ** usable_disks,dlist_t ** usable_slices)12360Sstevel@tonic-gate generate_usable_disks_and_slices_in_named_set(
12370Sstevel@tonic-gate char *dsname,
12380Sstevel@tonic-gate dlist_t **classes,
12390Sstevel@tonic-gate dlist_t **bad_slices,
12400Sstevel@tonic-gate dlist_t **usable_disks,
12410Sstevel@tonic-gate dlist_t **usable_slices)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate dlist_t *disks = NULL;
12440Sstevel@tonic-gate dlist_t *iter = NULL;
12450Sstevel@tonic-gate int error = 0;
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate error = get_disks_in_diskset(dsname, &disks);
12480Sstevel@tonic-gate if (error != 0) {
12490Sstevel@tonic-gate return (error);
12500Sstevel@tonic-gate }
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate /* For each disk... */
12530Sstevel@tonic-gate for (iter = disks;
12540Sstevel@tonic-gate iter != NULL && error == 0;
12550Sstevel@tonic-gate iter = iter->next) {
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj;
12580Sstevel@tonic-gate dlist_t *iter2;
12590Sstevel@tonic-gate dlist_t *slices = NULL;
12600Sstevel@tonic-gate dlist_t *bad_slices_on_this_disk = NULL;
12610Sstevel@tonic-gate dlist_t *used_slices_on_this_disk = NULL;
12620Sstevel@tonic-gate dlist_t *unused_slices_on_this_disk = NULL;
12630Sstevel@tonic-gate boolean_t bad_disk = B_FALSE;
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate error = disk_get_slices(disk, &slices);
12660Sstevel@tonic-gate if (error != 0) {
12670Sstevel@tonic-gate break;
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate /* Determine the used, unused, and bad slices on the disk */
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate /* For each slice... */
12730Sstevel@tonic-gate for (iter2 = slices;
12740Sstevel@tonic-gate iter2 != NULL && error == 0 && bad_disk == B_FALSE;
12750Sstevel@tonic-gate iter2 = iter2->next) {
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate dm_descriptor_t slice = (uintptr_t)iter2->obj;
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate boolean_t rsvd = B_FALSE;
12800Sstevel@tonic-gate boolean_t avail = B_FALSE;
12810Sstevel@tonic-gate
12820Sstevel@tonic-gate /* Get slice usage */
12830Sstevel@tonic-gate if (((error = is_reserved_slice(slice, &rsvd)) == 0) &&
12840Sstevel@tonic-gate ((error = check_slice_usage(dsname, slice, disk, &avail,
12850Sstevel@tonic-gate &bad_slices_on_this_disk, classes)) == 0)) {
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate /* Is the slice bad (inaccessible)? */
12880Sstevel@tonic-gate if (bad_slices_on_this_disk != NULL) {
12890Sstevel@tonic-gate *bad_slices = dlist_append_list(
12900Sstevel@tonic-gate *bad_slices, bad_slices_on_this_disk);
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate * Since one slice on this disk is bad, don't
12930Sstevel@tonic-gate * use any slices on this disk
12940Sstevel@tonic-gate */
12950Sstevel@tonic-gate bad_disk = B_TRUE;
12960Sstevel@tonic-gate } else {
12970Sstevel@tonic-gate
1298*62Sjeanm dlist_t *item =
1299*62Sjeanm dlist_new_item((void *)(uintptr_t)slice);
13000Sstevel@tonic-gate if (item == NULL) {
13010Sstevel@tonic-gate error = ENOMEM;
13020Sstevel@tonic-gate } else {
13030Sstevel@tonic-gate /* Add slice to used/unused list as appropriate */
13040Sstevel@tonic-gate if (avail == B_TRUE && rsvd == B_FALSE) {
13050Sstevel@tonic-gate unused_slices_on_this_disk = dlist_append(
13060Sstevel@tonic-gate item, unused_slices_on_this_disk, AT_TAIL);
13070Sstevel@tonic-gate } else {
13080Sstevel@tonic-gate used_slices_on_this_disk =
13090Sstevel@tonic-gate dlist_insert_ordered(item,
13100Sstevel@tonic-gate used_slices_on_this_disk,
13110Sstevel@tonic-gate ASCENDING, compare_start_blocks);
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate }
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate /* Done iterating slices */
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate if (error == 0 && bad_disk == B_FALSE) {
13210Sstevel@tonic-gate /* For each unused slice... */
13220Sstevel@tonic-gate for (iter2 = unused_slices_on_this_disk;
13230Sstevel@tonic-gate iter2 != NULL && error == 0;
13240Sstevel@tonic-gate iter2 = iter2->next) {
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate dm_descriptor_t slice = (uintptr_t)iter2->obj;
13270Sstevel@tonic-gate error = update_slice_attributes(slice, 0, 0, 0);
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate /* Only do this once */
13300Sstevel@tonic-gate if (error == 0 && iter2 == unused_slices_on_this_disk) {
13310Sstevel@tonic-gate error = add_modified_disk(NULL, disk);
13320Sstevel@tonic-gate }
13330Sstevel@tonic-gate }
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate if (error == 0) {
13360Sstevel@tonic-gate /* Create usable slices from the used/unused slice lists */
13370Sstevel@tonic-gate error = create_usable_slices(disk, used_slices_on_this_disk,
13380Sstevel@tonic-gate unused_slices_on_this_disk, usable_slices);
13390Sstevel@tonic-gate if (error == 0) {
1340*62Sjeanm error = dlist_append_object((void *)(uintptr_t)disk,
1341*62Sjeanm usable_disks, AT_TAIL);
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate dlist_free_items(slices, NULL);
13470Sstevel@tonic-gate dlist_free_items(used_slices_on_this_disk, NULL);
13480Sstevel@tonic-gate dlist_free_items(unused_slices_on_this_disk, NULL);
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate return (error);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate /*
13550Sstevel@tonic-gate * FUNCTION: create_usable_slices(dm_descriptor_t disk, dlist_t *used,
13560Sstevel@tonic-gate * dlist_t *unused, dlist_t **usable);
13570Sstevel@tonic-gate *
13580Sstevel@tonic-gate * INPUT: disk - a dm_descriptor_t disk handle
13590Sstevel@tonic-gate * used - pointer to a list of pvt_t structs
13600Sstevel@tonic-gate * representing existing used slices
13610Sstevel@tonic-gate * on the input disk.
13620Sstevel@tonic-gate * unused - pointer to a list of pvt_t structs
13630Sstevel@tonic-gate * representing existing unused slices
13640Sstevel@tonic-gate * on the input disk.
13650Sstevel@tonic-gate *
13660Sstevel@tonic-gate * OUTPUT: usable - pointer to a list of pvts representing slices
13670Sstevel@tonic-gate * which can be used for new volume layouts.
13680Sstevel@tonic-gate *
13690Sstevel@tonic-gate * Slices in this list have any available space on the
13700Sstevel@tonic-gate * disk collected into the fewest, lowest indexed slices
13710Sstevel@tonic-gate * possible.
13720Sstevel@tonic-gate *
13730Sstevel@tonic-gate * RETURNS: int - 0 on success
13740Sstevel@tonic-gate * !0 otherwise.
13750Sstevel@tonic-gate *
13760Sstevel@tonic-gate * PURPOSE: helper for generate_usable_slices_and_disks_in_diskset() which
13770Sstevel@tonic-gate * turns any detected free space on the input disk into one or
13780Sstevel@tonic-gate * more slices.
13790Sstevel@tonic-gate */
13800Sstevel@tonic-gate static int
create_usable_slices(dm_descriptor_t disk,dlist_t * used,dlist_t * unused,dlist_t ** usable)13810Sstevel@tonic-gate create_usable_slices(
13820Sstevel@tonic-gate dm_descriptor_t disk,
13830Sstevel@tonic-gate dlist_t *used,
13840Sstevel@tonic-gate dlist_t *unused,
13850Sstevel@tonic-gate dlist_t **usable)
13860Sstevel@tonic-gate {
13870Sstevel@tonic-gate dlist_t *iter;
13880Sstevel@tonic-gate int error = 0;
13890Sstevel@tonic-gate boolean_t first = B_TRUE;
13900Sstevel@tonic-gate dlist_t *next_unused = unused;
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate char *dname = NULL;
13930Sstevel@tonic-gate uint64_t disk_firstblk = 0;
13940Sstevel@tonic-gate uint64_t disk_nblks = 0;
13950Sstevel@tonic-gate uint64_t disk_endblk = 0;
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
13980Sstevel@tonic-gate gettext("\n create_usable_slices for disk\n"));
13990Sstevel@tonic-gate
14000Sstevel@tonic-gate /* get necessary info about disk: */
14010Sstevel@tonic-gate error = get_display_name(disk, &dname);
14020Sstevel@tonic-gate if (error != 0) {
14030Sstevel@tonic-gate return (error);
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate
14060Sstevel@tonic-gate /* disk start block is first usable block */
14070Sstevel@tonic-gate error = disk_get_start_block(disk, &disk_firstblk);
14080Sstevel@tonic-gate if (error != 0) {
14090Sstevel@tonic-gate return (error);
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate /* disk size determines last usable disk block */
14130Sstevel@tonic-gate error = disk_get_size_in_blocks(disk, &disk_nblks);
14140Sstevel@tonic-gate if (error != 0) {
14150Sstevel@tonic-gate return (error);
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate disk_endblk = disk_firstblk + disk_nblks - 1;
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate /* search for gaps before, between and after used slices */
14210Sstevel@tonic-gate for (iter = used; iter != NULL && error == 0; iter = iter->next) {
14220Sstevel@tonic-gate
14230Sstevel@tonic-gate dm_descriptor_t cur = (uintptr_t)iter->obj;
14240Sstevel@tonic-gate
14250Sstevel@tonic-gate uint64_t cur_stblk = 0;
14260Sstevel@tonic-gate uint64_t cur_nblks = 0;
14270Sstevel@tonic-gate uint64_t cur_endblk = 0;
14280Sstevel@tonic-gate uint32_t cur_index = 0;
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate uint64_t new_stblk = 0;
14310Sstevel@tonic-gate uint64_t new_endblk = 0;
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate char *sname = NULL;
14340Sstevel@tonic-gate (void) get_display_name(cur, &sname);
14350Sstevel@tonic-gate
14360Sstevel@tonic-gate if (((error = slice_get_index(cur, &cur_index)) != 0) ||
14370Sstevel@tonic-gate ((error = slice_get_start_block(cur, &cur_stblk)) != 0) ||
14380Sstevel@tonic-gate ((error = slice_get_size_in_blocks(cur, &cur_nblks)) != 0)) {
14390Sstevel@tonic-gate continue;
14400Sstevel@tonic-gate }
14410Sstevel@tonic-gate
14420Sstevel@tonic-gate cur_endblk = cur_stblk + cur_nblks - 1;
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
14450Sstevel@tonic-gate gettext(" used slice %d (%10llu to %10llu)\n"),
14460Sstevel@tonic-gate cur_index, cur_stblk, cur_endblk);
14470Sstevel@tonic-gate
14480Sstevel@tonic-gate if (first == B_TRUE) {
14490Sstevel@tonic-gate /* first slice: make sure it starts at disk_firstblk */
14500Sstevel@tonic-gate first = B_FALSE;
14510Sstevel@tonic-gate if (cur_stblk != disk_firstblk) {
14520Sstevel@tonic-gate /* close gap at beginning of disk */
14530Sstevel@tonic-gate new_stblk = disk_firstblk;
14540Sstevel@tonic-gate new_endblk = cur_stblk - 1;
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
14570Sstevel@tonic-gate gettext(" unused space before first "
14580Sstevel@tonic-gate "used slice\n"));
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate if (iter->next != NULL) {
14630Sstevel@tonic-gate /* check for gap between slices */
14640Sstevel@tonic-gate dm_descriptor_t next = (uintptr_t)iter->next->obj;
14650Sstevel@tonic-gate uint64_t next_stblk = 0;
14660Sstevel@tonic-gate uint32_t next_index = 0;
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate if (((error = slice_get_start_block(next, &next_stblk)) == 0) &&
14690Sstevel@tonic-gate ((error = slice_get_index(next, &next_index)) == 0)) {
14700Sstevel@tonic-gate if (cur_endblk != next_stblk - 1) {
14710Sstevel@tonic-gate /* close gap between slices */
14720Sstevel@tonic-gate new_stblk = cur_endblk + 1;
14730Sstevel@tonic-gate new_endblk = next_stblk - 1;
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
14760Sstevel@tonic-gate gettext(" unused space between slices "
14770Sstevel@tonic-gate "%d and %d\n"), cur_index, next_index);
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate }
14800Sstevel@tonic-gate
14810Sstevel@tonic-gate } else {
14820Sstevel@tonic-gate /* last slice: make sure it includes last block on disk */
14830Sstevel@tonic-gate if (cur_endblk != disk_endblk) {
14840Sstevel@tonic-gate /* close gap at end of disk */
14850Sstevel@tonic-gate new_stblk = cur_endblk + 1;
14860Sstevel@tonic-gate new_endblk = disk_endblk;
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
14890Sstevel@tonic-gate gettext(" unused space after last slice "
14900Sstevel@tonic-gate "cur_endblk: %llu disk_endblk: %llu\n"),
14910Sstevel@tonic-gate cur_endblk, disk_endblk);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate if ((error == 0) && (new_endblk != 0)) {
14960Sstevel@tonic-gate error = add_new_usable(disk, new_stblk,
14970Sstevel@tonic-gate new_endblk - new_stblk + 1, &next_unused, usable);
14980Sstevel@tonic-gate }
14990Sstevel@tonic-gate }
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate if (error != 0) {
15020Sstevel@tonic-gate dlist_free_items(*usable, free);
15030Sstevel@tonic-gate *usable = NULL;
15040Sstevel@tonic-gate }
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate return (error);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate /*
15100Sstevel@tonic-gate * FUNCTION: add_new_usable(dm_descriptor_t disk, uint64_t stblk,
15110Sstevel@tonic-gate * uint64_t nblks, dlist_t **next_unused,
15120Sstevel@tonic-gate * dlist_t **usable);
15130Sstevel@tonic-gate *
15140Sstevel@tonic-gate * INPUT: disk - a dm_descriptor_t disk handle
15150Sstevel@tonic-gate * stblk - start block of the usable space
15160Sstevel@tonic-gate * nblks - number of usable blocks
15170Sstevel@tonic-gate * next_unused - pointer to the next unused slice
15180Sstevel@tonic-gate *
15190Sstevel@tonic-gate * OUTPUT: next_unused - updated pointer to the next unused slice
15200Sstevel@tonic-gate * usable - possibly updated pointer to a list of slices on
15210Sstevel@tonic-gate * the disk with usable space
15220Sstevel@tonic-gate *
15230Sstevel@tonic-gate * RETURNS: int - 0 on success
15240Sstevel@tonic-gate * !0 otherwise.
15250Sstevel@tonic-gate *
15260Sstevel@tonic-gate * PURPOSE: helper for create_usable_slices() which turns free space
15270Sstevel@tonic-gate * on the input disk into a usable slice.
15280Sstevel@tonic-gate *
15290Sstevel@tonic-gate * If possible an existing unused slice will be recycled
15300Sstevel@tonic-gate * into a usable slice. If there are none, a new virtual
15310Sstevel@tonic-gate * slice will be created.
15320Sstevel@tonic-gate */
15330Sstevel@tonic-gate static int
add_new_usable(dm_descriptor_t disk,uint64_t stblk,uint64_t nblks,dlist_t ** next_unused,dlist_t ** usable)15340Sstevel@tonic-gate add_new_usable(
15350Sstevel@tonic-gate dm_descriptor_t disk,
15360Sstevel@tonic-gate uint64_t stblk,
15370Sstevel@tonic-gate uint64_t nblks,
15380Sstevel@tonic-gate dlist_t **next_unused,
15390Sstevel@tonic-gate dlist_t **usable)
15400Sstevel@tonic-gate {
15410Sstevel@tonic-gate dm_descriptor_t new_usable = 0;
15420Sstevel@tonic-gate int error = 0;
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate /* try to use an existing unused slice for the usable slice */
15450Sstevel@tonic-gate if (*next_unused != NULL) {
15460Sstevel@tonic-gate new_usable = (uintptr_t)((*next_unused)->obj);
15470Sstevel@tonic-gate *next_unused = (*next_unused)->next;
15480Sstevel@tonic-gate
15490Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
15500Sstevel@tonic-gate gettext("\trecyling used slice into usable slice "
15510Sstevel@tonic-gate "start: %llu, end: %llu\n"),
15520Sstevel@tonic-gate stblk, stblk + nblks + 1);
15530Sstevel@tonic-gate }
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate if (new_usable == NULL) {
15560Sstevel@tonic-gate /* no unused slices, try to make a new virtual slice */
15570Sstevel@tonic-gate uint32_t index = UINT32_MAX;
15580Sstevel@tonic-gate error = disk_get_available_slice_index(disk, &index);
15590Sstevel@tonic-gate if ((error == 0) && (index != UINT32_MAX)) {
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate char *dname = NULL;
15620Sstevel@tonic-gate error = get_display_name(disk, &dname);
15630Sstevel@tonic-gate if (error == 0) {
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate char buf[MAXNAMELEN];
15660Sstevel@tonic-gate (void) snprintf(buf, MAXNAMELEN-1, "%ss%d", dname, index);
15670Sstevel@tonic-gate error = add_virtual_slice(buf, index, 0, 0, disk);
15680Sstevel@tonic-gate if (error == 0) {
15690Sstevel@tonic-gate /* retrieve the virtual slice */
15700Sstevel@tonic-gate error = slice_get_by_name(buf, &new_usable);
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate }
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate }
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate if ((error == 0) && (new_usable != (dm_descriptor_t)0)) {
15770Sstevel@tonic-gate /* BEGIN CSTYLED */
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate * have an unused slice, update its attributes to reflect
15800Sstevel@tonic-gate * the usable space it represents
15810Sstevel@tonic-gate */
15820Sstevel@tonic-gate /* END CSTYLED */
15830Sstevel@tonic-gate uint64_t disk_blksz = 0;
15840Sstevel@tonic-gate error = disk_get_blocksize(disk, &disk_blksz);
15850Sstevel@tonic-gate if (error == 0) {
15860Sstevel@tonic-gate error = update_slice_attributes(new_usable, stblk,
15870Sstevel@tonic-gate nblks, nblks * disk_blksz);
15880Sstevel@tonic-gate if (error == 0) {
15890Sstevel@tonic-gate error = dlist_append_object(
1590*62Sjeanm (void *)(uintptr_t)new_usable, usable, AT_TAIL);
15910Sstevel@tonic-gate }
15920Sstevel@tonic-gate }
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate return (error);
15960Sstevel@tonic-gate }
15970Sstevel@tonic-gate
15980Sstevel@tonic-gate /*
15990Sstevel@tonic-gate * FUNCTION: update_slice_attributes(dm_descriptor_t slice, uint64_t stblk,
16000Sstevel@tonic-gate * uint64_t nblks, uint64_t nbytes)
16010Sstevel@tonic-gate *
16020Sstevel@tonic-gate * INPUT: slice - a dm_descriptor_t slice handle
16030Sstevel@tonic-gate * stblk - start block of the usable space
16040Sstevel@tonic-gate * nblks - size of slice in blocks
16050Sstevel@tonic-gate * nbytes - size of slice in bytes
16060Sstevel@tonic-gate *
16070Sstevel@tonic-gate * SIDEEFFECT: adds a modification record for the slice.
16080Sstevel@tonic-gate *
16090Sstevel@tonic-gate * RETURNS: int - 0 on success
16100Sstevel@tonic-gate * !0 otherwise.
16110Sstevel@tonic-gate *
16120Sstevel@tonic-gate * PURPOSE: utility which updates several slice attributes in one call.
16130Sstevel@tonic-gate */
16140Sstevel@tonic-gate static int
update_slice_attributes(dm_descriptor_t slice,uint64_t stblk,uint64_t nblks,uint64_t nbytes)16150Sstevel@tonic-gate update_slice_attributes(
16160Sstevel@tonic-gate dm_descriptor_t slice,
16170Sstevel@tonic-gate uint64_t stblk,
16180Sstevel@tonic-gate uint64_t nblks,
16190Sstevel@tonic-gate uint64_t nbytes)
16200Sstevel@tonic-gate {
16210Sstevel@tonic-gate char *sname = NULL;
16220Sstevel@tonic-gate uint32_t index = 0;
16230Sstevel@tonic-gate int error = 0;
16240Sstevel@tonic-gate
16250Sstevel@tonic-gate if ((error = get_display_name(slice, &sname)) == 0) {
16260Sstevel@tonic-gate if ((error = slice_get_index(slice, &index)) == 0) {
16270Sstevel@tonic-gate if ((error = slice_set_start_block(slice, stblk)) == 0) {
16280Sstevel@tonic-gate if ((error = slice_set_size_in_blocks(slice, nblks)) == 0) {
16290Sstevel@tonic-gate if (nblks == 0) {
16300Sstevel@tonic-gate error = add_slice_to_remove(sname, index);
16310Sstevel@tonic-gate } else {
16320Sstevel@tonic-gate error = assemble_modified_slice((dm_descriptor_t)0,
16330Sstevel@tonic-gate sname, index, stblk, nblks, nbytes, NULL);
16340Sstevel@tonic-gate }
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate }
16380Sstevel@tonic-gate }
16390Sstevel@tonic-gate
16400Sstevel@tonic-gate return (error);
16410Sstevel@tonic-gate }
16420Sstevel@tonic-gate
16430Sstevel@tonic-gate /*
16440Sstevel@tonic-gate * FUNCTION: generate_usable_hbas(dlist_t *slices,
16450Sstevel@tonic-gate * dlist_t **usable)
16460Sstevel@tonic-gate *
16470Sstevel@tonic-gate * INPUT: disks - a list of usable disks.
16480Sstevel@tonic-gate *
16490Sstevel@tonic-gate * OUTPUT: usable - a populated list of usable HBAs.
16500Sstevel@tonic-gate *
16510Sstevel@tonic-gate * RETURNS: int - 0 on success
16520Sstevel@tonic-gate * !0 otherwise
16530Sstevel@tonic-gate *
16540Sstevel@tonic-gate * PURPOSE: Examines usable disk list and derives the list of usable HBAs.
16550Sstevel@tonic-gate *
16560Sstevel@tonic-gate */
16570Sstevel@tonic-gate static int
generate_usable_hbas(dlist_t * disks,dlist_t ** usable)16580Sstevel@tonic-gate generate_usable_hbas(
16590Sstevel@tonic-gate dlist_t *disks,
16600Sstevel@tonic-gate dlist_t **usable)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate dlist_t *iter;
16630Sstevel@tonic-gate int error = 0;
16640Sstevel@tonic-gate
16650Sstevel@tonic-gate /*
16660Sstevel@tonic-gate * for each usable disk, follow its HBA connections and
16670Sstevel@tonic-gate * add them to the list of usable HBAs.
16680Sstevel@tonic-gate */
16690Sstevel@tonic-gate for (iter = disks; (iter != NULL) && (error == 0); iter = iter->next) {
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate dm_descriptor_t dp = NULL;
16720Sstevel@tonic-gate dlist_t *hbas = NULL;
16730Sstevel@tonic-gate dlist_t *iter2 = NULL;
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate dp = (uintptr_t)iter->obj;
16760Sstevel@tonic-gate
16770Sstevel@tonic-gate error = disk_get_hbas(dp, &hbas);
16780Sstevel@tonic-gate if (error == 0) {
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate for (iter2 = hbas;
16810Sstevel@tonic-gate (iter2 != NULL) && (error == 0);
16820Sstevel@tonic-gate iter2 = iter2->next) {
16830Sstevel@tonic-gate
16840Sstevel@tonic-gate dm_descriptor_t hba = (uintptr_t)iter2->obj;
16850Sstevel@tonic-gate dlist_t *item = NULL;
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate /* scan list of usable HBAs and see if known */
1688*62Sjeanm if (dlist_contains(*usable, (void*)(uintptr_t)hba,
1689*62Sjeanm compare_descriptor_names) == B_TRUE) {
16900Sstevel@tonic-gate /* known HBA, continue to next HBA/alias */
16910Sstevel@tonic-gate continue;
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /* add this HBA to the usable list */
1695*62Sjeanm if ((item = dlist_new_item((void *)(uintptr_t)hba)) ==
1696*62Sjeanm NULL) {
16970Sstevel@tonic-gate error = ENOMEM;
16980Sstevel@tonic-gate } else {
16990Sstevel@tonic-gate *usable =
17000Sstevel@tonic-gate dlist_insert_ordered(item, *usable,
17010Sstevel@tonic-gate ASCENDING, compare_desc_display_names);
17020Sstevel@tonic-gate }
17030Sstevel@tonic-gate }
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate dlist_free_items(hbas, NULL);
17070Sstevel@tonic-gate }
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate return (error);
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate /*
17130Sstevel@tonic-gate * FUNCTION: check_slice_usage(char *dsname, dm_descriptor_t slice,
17140Sstevel@tonic-gate * dm_descriptor_t disk, boolean_t *avail,
17150Sstevel@tonic-gate * dlist_t **bad, dlist_t **classes)
17160Sstevel@tonic-gate *
17170Sstevel@tonic-gate * INPUT: dsname - a char * diskset name.
17180Sstevel@tonic-gate * slice - a dm_descriptor_t handle for a known slices.
17190Sstevel@tonic-gate * disk - a dm_descriptor_t handle the slice's disk.
17200Sstevel@tonic-gate *
17210Sstevel@tonic-gate * OUTPUT: avail - a boolean_t to hold the slice's availability.
17220Sstevel@tonic-gate * bad - pointer to a list of bad/unusable slices,
17230Sstevel@tonic-gate * possibly updated if the input slice
17240Sstevel@tonic-gate * was determined to be inaccessible.
17250Sstevel@tonic-gate * classes - pointer to a list of slice_class_t structs,
17260Sstevel@tonic-gate * possibly updated to include the input slice
17270Sstevel@tonic-gate * if it has a known use.
17280Sstevel@tonic-gate *
17290Sstevel@tonic-gate * RETURNS: int - 0 on success
17300Sstevel@tonic-gate * !0 otherwise.
17310Sstevel@tonic-gate *
17320Sstevel@tonic-gate * PURPOSE: Handles the details of
17330Sstevel@tonic-gate * determining usage and/or availability of a single slice.
17340Sstevel@tonic-gate *
17350Sstevel@tonic-gate * Queries the device library for the input slice's detectable
17360Sstevel@tonic-gate * usage status.
17370Sstevel@tonic-gate *
17380Sstevel@tonic-gate * If the slice has a detected usage, its name is added to
17390Sstevel@tonic-gate * the appropriate slice_class_t list in the input list of
17400Sstevel@tonic-gate * slice classes, this is only done if verbose output was
17410Sstevel@tonic-gate * requested.
17420Sstevel@tonic-gate */
17430Sstevel@tonic-gate static int
check_slice_usage(char * dsname,dm_descriptor_t slice,dm_descriptor_t disk,boolean_t * avail,dlist_t ** bad,dlist_t ** classes)17440Sstevel@tonic-gate check_slice_usage(
17450Sstevel@tonic-gate char *dsname,
17460Sstevel@tonic-gate dm_descriptor_t slice,
17470Sstevel@tonic-gate dm_descriptor_t disk,
17480Sstevel@tonic-gate boolean_t *avail,
17490Sstevel@tonic-gate dlist_t **bad,
17500Sstevel@tonic-gate dlist_t **classes)
17510Sstevel@tonic-gate {
17520Sstevel@tonic-gate boolean_t online = B_FALSE;
17530Sstevel@tonic-gate boolean_t used = B_FALSE;
17540Sstevel@tonic-gate nvlist_t *stats = NULL;
17550Sstevel@tonic-gate char *name = NULL;
17560Sstevel@tonic-gate char *used_by = NULL;
17570Sstevel@tonic-gate char *use_detail = NULL;
17580Sstevel@tonic-gate int error = 0;
17590Sstevel@tonic-gate
17600Sstevel@tonic-gate *avail = B_FALSE;
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate if (((error = get_display_name(slice, &name)) != 0) ||
17630Sstevel@tonic-gate (error = disk_get_is_online(disk, &online))) {
17640Sstevel@tonic-gate return (error);
17650Sstevel@tonic-gate }
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate /*
17680Sstevel@tonic-gate * if the disk is known to be offline, skip getting status
17690Sstevel@tonic-gate * for the slice since it will just fail and return ENODEV.
17700Sstevel@tonic-gate */
17710Sstevel@tonic-gate if (online != B_TRUE) {
17720Sstevel@tonic-gate error = ENODEV;
17730Sstevel@tonic-gate } else {
17740Sstevel@tonic-gate stats = dm_get_stats(slice, DM_SLICE_STAT_USE, &error);
17750Sstevel@tonic-gate }
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate if (error != 0) {
17780Sstevel@tonic-gate if (error == ENODEV) {
1779*62Sjeanm dlist_t *item = dlist_new_item((void *)(uintptr_t)slice);
17800Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
17810Sstevel@tonic-gate gettext("Warning: unable to get slice information "
17820Sstevel@tonic-gate "for %s, it will not be used.\n"), name);
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate if (item == NULL) {
17850Sstevel@tonic-gate error = ENOMEM;
17860Sstevel@tonic-gate } else {
17870Sstevel@tonic-gate error = 0;
17880Sstevel@tonic-gate *bad = dlist_insert_ordered(item, *bad, ASCENDING,
17890Sstevel@tonic-gate compare_desc_display_names);
17900Sstevel@tonic-gate }
17910Sstevel@tonic-gate } else {
17920Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
17930Sstevel@tonic-gate gettext("check_slice_usage: dm_get_stats for "
17940Sstevel@tonic-gate "%s failed %d\n"),
17950Sstevel@tonic-gate name, error);
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate
17980Sstevel@tonic-gate return (error);
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate
18010Sstevel@tonic-gate /*
18020Sstevel@tonic-gate * check if/how the slice is currently being used,
18030Sstevel@tonic-gate * device library provides this info in the nvpair_t list:
18040Sstevel@tonic-gate *
18050Sstevel@tonic-gate * stat_type is DM_SLICE_STAT_USE
18060Sstevel@tonic-gate * used_by: string (mount, svm, lu, vxvm, fs)
18070Sstevel@tonic-gate * used_name: string
18080Sstevel@tonic-gate *
18090Sstevel@tonic-gate */
18100Sstevel@tonic-gate if (stats != NULL) {
18110Sstevel@tonic-gate error = get_string(stats, DM_USED_BY, &used_by);
18120Sstevel@tonic-gate if (error != 0) {
18130Sstevel@tonic-gate if (error == ENOENT) {
18140Sstevel@tonic-gate used_by = NULL;
18150Sstevel@tonic-gate error = 0;
18160Sstevel@tonic-gate } else {
18170Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
18180Sstevel@tonic-gate gettext("check_slice_usage: dm_get_stats.%s for "
18190Sstevel@tonic-gate "%s failed %d\n"),
18200Sstevel@tonic-gate DM_USED_BY, name, error);
18210Sstevel@tonic-gate }
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate
18240Sstevel@tonic-gate if (error == 0) {
18250Sstevel@tonic-gate error = get_string(stats, DM_USED_NAME, &use_detail);
18260Sstevel@tonic-gate if (error != 0) {
18270Sstevel@tonic-gate if (error == ENOENT) {
18280Sstevel@tonic-gate use_detail = NULL;
18290Sstevel@tonic-gate error = 0;
18300Sstevel@tonic-gate } else {
18310Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
18320Sstevel@tonic-gate gettext("check_slice_usage: "
18330Sstevel@tonic-gate "dm_get_stats.%s for "
18340Sstevel@tonic-gate "%s failed %d\n"),
18350Sstevel@tonic-gate DM_USED_NAME, name, error);
18360Sstevel@tonic-gate }
18370Sstevel@tonic-gate }
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate if ((error == 0) && (used_by != NULL) && (used_by[0] != '\0')) {
18420Sstevel@tonic-gate
18430Sstevel@tonic-gate /* was detected usage SVM? */
18440Sstevel@tonic-gate if (string_case_compare(used_by, DM_USE_SVM) == 0) {
18450Sstevel@tonic-gate
18460Sstevel@tonic-gate /* check use_detail, it is in the form diskset:name */
18470Sstevel@tonic-gate if (strncmp("diskset:", use_detail, 8) == 0) {
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate /* check disk set name */
18500Sstevel@tonic-gate char *str = strrchr(use_detail, ':');
18510Sstevel@tonic-gate if ((str != NULL) &&
18520Sstevel@tonic-gate (string_case_compare(str+1, dsname) == 0)) {
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate /* slice in the right diskset */
18550Sstevel@tonic-gate error = check_svm_slice_usage(
18560Sstevel@tonic-gate dsname, slice, disk, &used, classes);
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate } else {
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate /* slice in other diskset */
18610Sstevel@tonic-gate save_slice_classification(
18620Sstevel@tonic-gate dsname, slice, disk, used_by, use_detail,
18630Sstevel@tonic-gate classes);
18640Sstevel@tonic-gate used = B_TRUE;
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate } else {
18680Sstevel@tonic-gate
18690Sstevel@tonic-gate /* slice is volume component */
18700Sstevel@tonic-gate save_slice_classification(
18710Sstevel@tonic-gate dsname, slice, disk, used_by, use_detail,
18720Sstevel@tonic-gate classes);
18730Sstevel@tonic-gate used = B_TRUE;
18740Sstevel@tonic-gate }
18750Sstevel@tonic-gate
18760Sstevel@tonic-gate } else {
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate /* save usage */
18790Sstevel@tonic-gate save_slice_classification(
18800Sstevel@tonic-gate dsname, slice, disk, used_by, use_detail,
18810Sstevel@tonic-gate classes);
18820Sstevel@tonic-gate used = B_TRUE;
18830Sstevel@tonic-gate }
18840Sstevel@tonic-gate }
18850Sstevel@tonic-gate
18860Sstevel@tonic-gate nvlist_free(stats);
18870Sstevel@tonic-gate
18880Sstevel@tonic-gate if (error == 0) {
18890Sstevel@tonic-gate if (used == B_TRUE) {
18900Sstevel@tonic-gate *avail = B_FALSE;
18910Sstevel@tonic-gate } else {
18920Sstevel@tonic-gate *avail = B_TRUE;
18930Sstevel@tonic-gate }
18940Sstevel@tonic-gate }
18950Sstevel@tonic-gate
18960Sstevel@tonic-gate return (error);
18970Sstevel@tonic-gate }
18980Sstevel@tonic-gate
18990Sstevel@tonic-gate /*
19000Sstevel@tonic-gate * FUNCTION: check_svm_slice_usage(char *dsname, dm_descriptor_t slice,
19010Sstevel@tonic-gate * dm_descriptor_t disk, boolean_t *used,
19020Sstevel@tonic-gate * dlist_t **classes)
19030Sstevel@tonic-gate *
19040Sstevel@tonic-gate * INPUT: dsname - a char * diskset name.
19050Sstevel@tonic-gate * slice - a dm_descriptor_t handle for a known slices.
19060Sstevel@tonic-gate * disk - a dm_descriptor_t handle the slice's disk.
19070Sstevel@tonic-gate *
19080Sstevel@tonic-gate * OUTPUT: used - a boolean_t to hold the slice usage status.
19090Sstevel@tonic-gate * classes - pointer to a list of slice_class_t possibly updated
19100Sstevel@tonic-gate * with the input slice's SVM specific usage
19110Sstevel@tonic-gate * classification.
19120Sstevel@tonic-gate *
19130Sstevel@tonic-gate * RETURNS: int - 0 on success
19140Sstevel@tonic-gate * !0 otherwise.
19150Sstevel@tonic-gate *
19160Sstevel@tonic-gate * PURPOSE: Handles the finer details of
19170Sstevel@tonic-gate * a single slice is being used in the context of SVM.
19180Sstevel@tonic-gate *
19190Sstevel@tonic-gate * Currently, one thing is checked:
19200Sstevel@tonic-gate *
19210Sstevel@tonic-gate * 1. determine if the slice is reserved for metadb replicas.
19220Sstevel@tonic-gate * The convention for disks in disksets is that a single slice
19230Sstevel@tonic-gate * (index 6 or 7) is set aside for metadb replicas.
19240Sstevel@tonic-gate *
19250Sstevel@tonic-gate * If this condition does not hold, the slice is considered
19260Sstevel@tonic-gate * available for use by layout and 'used' is set to B_FALSE.
19270Sstevel@tonic-gate */
19280Sstevel@tonic-gate static int
check_svm_slice_usage(char * dsname,dm_descriptor_t slice,dm_descriptor_t disk,boolean_t * used,dlist_t ** classes)19290Sstevel@tonic-gate check_svm_slice_usage(
19300Sstevel@tonic-gate char *dsname,
19310Sstevel@tonic-gate dm_descriptor_t slice,
19320Sstevel@tonic-gate dm_descriptor_t disk,
19330Sstevel@tonic-gate boolean_t *used,
19340Sstevel@tonic-gate dlist_t **classes)
19350Sstevel@tonic-gate {
19360Sstevel@tonic-gate boolean_t is_replica = B_FALSE;
19370Sstevel@tonic-gate uint32_t index = 0;
19380Sstevel@tonic-gate char *diskname = NULL;
19390Sstevel@tonic-gate int error = 0;
19400Sstevel@tonic-gate
19410Sstevel@tonic-gate ((error = slice_get_index(slice, &index)) != 0) ||
19420Sstevel@tonic-gate (error = get_display_name(disk, &diskname)) ||
19430Sstevel@tonic-gate (error = is_reserved_replica_slice_index(
19440Sstevel@tonic-gate dsname, diskname, index, &is_replica));
19450Sstevel@tonic-gate
19460Sstevel@tonic-gate if (error == 0) {
19470Sstevel@tonic-gate if (is_replica == B_TRUE) {
19480Sstevel@tonic-gate /* is replica slice -> used */
19490Sstevel@tonic-gate save_slice_classification(dsname, slice, disk, DM_USE_SVM,
19500Sstevel@tonic-gate gettext("reserved for metadb replicas"), classes);
19510Sstevel@tonic-gate *used = B_TRUE;
19520Sstevel@tonic-gate } else {
19530Sstevel@tonic-gate *used = B_FALSE;
19540Sstevel@tonic-gate }
19550Sstevel@tonic-gate }
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate return (error);
19580Sstevel@tonic-gate }
19590Sstevel@tonic-gate
19600Sstevel@tonic-gate /*
19610Sstevel@tonic-gate * FUNCTION: save_slice_classification(char *dsname, dm_descriptor_t slice,
19620Sstevel@tonic-gate * dm_descriptor_t disk, char *used_by, char *usage_detail,
19630Sstevel@tonic-gate * dlist_t **classes)
19640Sstevel@tonic-gate *
19650Sstevel@tonic-gate * INPUT: dsname - a char * disk set name
19660Sstevel@tonic-gate * slice - a dm_descriptor_t slice handle.
19670Sstevel@tonic-gate * disk - a dm_descriptor_t handle for the slice's disk.
19680Sstevel@tonic-gate * used_by - a char * usage classification.
19690Sstevel@tonic-gate * usage_detail - a char * usage description for the slice.
19700Sstevel@tonic-gate *
19710Sstevel@tonic-gate * OUTPUT: classes - a list of slice_class_t updated to hold a usage
19720Sstevel@tonic-gate * entry for the input slicexs.
19730Sstevel@tonic-gate *
19740Sstevel@tonic-gate * SIDEEFFECT: adds the input slice to the list of known, used slices.
19750Sstevel@tonic-gate *
19760Sstevel@tonic-gate * RETURNS: int - 0 on success
19770Sstevel@tonic-gate * !0 otherwise.
19780Sstevel@tonic-gate *
19790Sstevel@tonic-gate * PURPOSE: Adds an entry to the
19800Sstevel@tonic-gate * appropriate slice_class_t list of slices. If there is
19810Sstevel@tonic-gate * not an appropriate slice_class_t entry in the input list
19820Sstevel@tonic-gate * of classes, one is added.
19830Sstevel@tonic-gate *
19840Sstevel@tonic-gate * As a performance optimization the slice usage classification
19850Sstevel@tonic-gate * information is only saved if verbose output was requested by
19860Sstevel@tonic-gate * the user.
19870Sstevel@tonic-gate */
19880Sstevel@tonic-gate static int
save_slice_classification(char * dsname,dm_descriptor_t slice,dm_descriptor_t disk,char * usage,char * usage_detail,dlist_t ** classes)19890Sstevel@tonic-gate save_slice_classification(
19900Sstevel@tonic-gate char *dsname,
19910Sstevel@tonic-gate dm_descriptor_t slice,
19920Sstevel@tonic-gate dm_descriptor_t disk,
19930Sstevel@tonic-gate char *usage,
19940Sstevel@tonic-gate char *usage_detail,
19950Sstevel@tonic-gate dlist_t **classes)
19960Sstevel@tonic-gate {
19970Sstevel@tonic-gate int error = 0;
19980Sstevel@tonic-gate
19990Sstevel@tonic-gate error = add_used_slice(slice);
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate if ((error == 0) && (get_max_verbosity() >= OUTPUT_VERBOSE)) {
20020Sstevel@tonic-gate
20030Sstevel@tonic-gate dlist_t *iter;
20040Sstevel@tonic-gate dlist_t *item;
20050Sstevel@tonic-gate slice_class_t *class = NULL;
20060Sstevel@tonic-gate
20070Sstevel@tonic-gate /* locate class struct matching 'usage' */
20080Sstevel@tonic-gate for (iter = *classes; iter != NULL; iter = iter->next) {
20090Sstevel@tonic-gate class = (slice_class_t *)iter->obj;
20100Sstevel@tonic-gate if (string_case_compare(usage, class->usage) == 0) {
20110Sstevel@tonic-gate break;
20120Sstevel@tonic-gate }
20130Sstevel@tonic-gate }
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate if (iter == NULL) {
20160Sstevel@tonic-gate /* add a new class to the list of classes */
20170Sstevel@tonic-gate class = (slice_class_t *)calloc(1, sizeof (slice_class_t));
20180Sstevel@tonic-gate if (class == NULL) {
20190Sstevel@tonic-gate error = ENOMEM;
20200Sstevel@tonic-gate } else {
20210Sstevel@tonic-gate class->usage = strdup(usage);
20220Sstevel@tonic-gate if (class->usage == NULL) {
20230Sstevel@tonic-gate free(class);
20240Sstevel@tonic-gate class = NULL;
20250Sstevel@tonic-gate error = ENOMEM;
20260Sstevel@tonic-gate } else {
20270Sstevel@tonic-gate item = dlist_new_item((void *)class);
20280Sstevel@tonic-gate if (item == NULL) {
20290Sstevel@tonic-gate free(class->usage);
20300Sstevel@tonic-gate free(class);
20310Sstevel@tonic-gate class = NULL;
20320Sstevel@tonic-gate error = ENOMEM;
20330Sstevel@tonic-gate } else {
20340Sstevel@tonic-gate *classes = dlist_append(item, *classes, AT_TAIL);
20350Sstevel@tonic-gate }
20360Sstevel@tonic-gate }
20370Sstevel@tonic-gate }
20380Sstevel@tonic-gate }
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate if ((error == 0) && (class != NULL)) {
20410Sstevel@tonic-gate
20420Sstevel@tonic-gate char buf[BUFSIZ];
20430Sstevel@tonic-gate char *dup = NULL;
20440Sstevel@tonic-gate char *slicename = NULL;
20450Sstevel@tonic-gate
20460Sstevel@tonic-gate (void) get_display_name(slice, &slicename);
20470Sstevel@tonic-gate (void) snprintf(buf, BUFSIZ-1, " %s: %s",
20480Sstevel@tonic-gate slicename, usage_detail);
20490Sstevel@tonic-gate if ((dup = strdup(buf)) == NULL) {
20500Sstevel@tonic-gate error = ENOMEM;
20510Sstevel@tonic-gate } else {
20520Sstevel@tonic-gate if ((item = dlist_new_item((void *)dup)) == NULL) {
20530Sstevel@tonic-gate free(dup);
20540Sstevel@tonic-gate error = ENOMEM;
20550Sstevel@tonic-gate } else {
20560Sstevel@tonic-gate class->sliceinfo =
20570Sstevel@tonic-gate dlist_insert_ordered(
20580Sstevel@tonic-gate item, class->sliceinfo,
20590Sstevel@tonic-gate ASCENDING, compare_strings);
20600Sstevel@tonic-gate }
20610Sstevel@tonic-gate }
20620Sstevel@tonic-gate }
20630Sstevel@tonic-gate }
20640Sstevel@tonic-gate
20650Sstevel@tonic-gate return (error);
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate
20680Sstevel@tonic-gate /*
20690Sstevel@tonic-gate * FUNCTION: print_usable_devices()
20700Sstevel@tonic-gate *
20710Sstevel@tonic-gate * PURPOSE: Print out the devices determined to be available for
20720Sstevel@tonic-gate * use by layout.
20730Sstevel@tonic-gate *
20740Sstevel@tonic-gate * Iterates the lists of usable slices, disks and HBAs
20750Sstevel@tonic-gate * and prints out their CTD and device names.
20760Sstevel@tonic-gate */
20770Sstevel@tonic-gate static void
print_usable_devices()20780Sstevel@tonic-gate print_usable_devices()
20790Sstevel@tonic-gate {
20800Sstevel@tonic-gate int i = 0;
20810Sstevel@tonic-gate
20820Sstevel@tonic-gate struct {
20830Sstevel@tonic-gate char *msg;
20840Sstevel@tonic-gate dlist_t *list;
20850Sstevel@tonic-gate } devs[3];
20860Sstevel@tonic-gate
20870Sstevel@tonic-gate devs[0].msg = gettext("HBA/Controllers");
20880Sstevel@tonic-gate devs[0].list = _usable_hbas;
20890Sstevel@tonic-gate devs[1].msg = gettext("disks");
20900Sstevel@tonic-gate devs[1].list = _usable_disks;
20910Sstevel@tonic-gate devs[2].msg = gettext("slices");
20920Sstevel@tonic-gate devs[2].list = _usable_slices;
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate for (i = 0; i < 3; i++) {
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
20970Sstevel@tonic-gate gettext("\n These %s are usable:\n\n"),
20980Sstevel@tonic-gate devs[i].msg);
20990Sstevel@tonic-gate
21000Sstevel@tonic-gate print_device_list(devs[i].list);
21010Sstevel@tonic-gate }
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate
21040Sstevel@tonic-gate /*
21050Sstevel@tonic-gate * FUNCTION: print_device_list(dlist_t *devices)
21060Sstevel@tonic-gate *
21070Sstevel@tonic-gate * INPUT: devices - a list of device descriptor handles
21080Sstevel@tonic-gate *
21090Sstevel@tonic-gate * PURPOSE: A helper for the print_XXX_devices() routines which iterates
21100Sstevel@tonic-gate * the input list and prints out each device name, CTD name and
21110Sstevel@tonic-gate * alias(es).
21120Sstevel@tonic-gate */
21130Sstevel@tonic-gate static void
print_device_list(dlist_t * devices)21140Sstevel@tonic-gate print_device_list(
21150Sstevel@tonic-gate dlist_t *devices)
21160Sstevel@tonic-gate {
21170Sstevel@tonic-gate dlist_t *iter = NULL;
21180Sstevel@tonic-gate
21190Sstevel@tonic-gate for (iter = devices; iter != NULL; iter = iter->next) {
21200Sstevel@tonic-gate
21210Sstevel@tonic-gate dm_descriptor_t device = ((uintptr_t)iter->obj);
21220Sstevel@tonic-gate char *name = NULL;
21230Sstevel@tonic-gate char *ctd = NULL;
21240Sstevel@tonic-gate dlist_t *aliases = NULL;
21250Sstevel@tonic-gate
21260Sstevel@tonic-gate (void) get_display_name(device, &ctd);
21270Sstevel@tonic-gate (void) get_name(device, &name);
21280Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
21290Sstevel@tonic-gate " %-25s %s\n", (ctd != NULL ? ctd : ""), name);
21300Sstevel@tonic-gate
21310Sstevel@tonic-gate (void) get_aliases(device, &aliases);
21320Sstevel@tonic-gate for (; aliases != NULL; aliases = aliases->next) {
21330Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
21340Sstevel@tonic-gate gettext(" (alias: %s)\n"),
21350Sstevel@tonic-gate (char *)aliases->obj);
21360Sstevel@tonic-gate }
21370Sstevel@tonic-gate
21380Sstevel@tonic-gate dlist_free_items(aliases, free);
21390Sstevel@tonic-gate }
21400Sstevel@tonic-gate }
21410Sstevel@tonic-gate
21420Sstevel@tonic-gate /*
21430Sstevel@tonic-gate * FUNCTION: print_unusable_devices(
21440Sstevel@tonic-gate * dlist_t *bad_slices, dlist_t *bad_disks,
21450Sstevel@tonic-gate * dlist_t *used_classes)
21460Sstevel@tonic-gate *
21470Sstevel@tonic-gate * INPUT: used_classes - a list of slice_class_t structs
21480Sstevel@tonic-gate *
21490Sstevel@tonic-gate * PURPOSE: Print out the devices determined to be unavailable for
21500Sstevel@tonic-gate * use by layout.
21510Sstevel@tonic-gate *
21520Sstevel@tonic-gate * Iterates the input list of slice classifications and prints
21530Sstevel@tonic-gate * out a description of the class and the slices so classified.
21540Sstevel@tonic-gate *
21550Sstevel@tonic-gate * Also iterates the lists of bad slices and disks (those that
21560Sstevel@tonic-gate * libdiskmgt returned descriptors for but cannot be accessed)
21570Sstevel@tonic-gate * and notes them as unusable.
21580Sstevel@tonic-gate */
21590Sstevel@tonic-gate static void
print_unusable_devices(dlist_t * bad_slices,dlist_t * bad_disks,dlist_t * used_classes)21600Sstevel@tonic-gate print_unusable_devices(
21610Sstevel@tonic-gate dlist_t *bad_slices,
21620Sstevel@tonic-gate dlist_t *bad_disks,
21630Sstevel@tonic-gate dlist_t *used_classes)
21640Sstevel@tonic-gate {
21650Sstevel@tonic-gate dlist_t *iter = NULL;
21660Sstevel@tonic-gate dlist_t *slices = NULL;
21670Sstevel@tonic-gate char *preamble;
21680Sstevel@tonic-gate
21690Sstevel@tonic-gate struct {
21700Sstevel@tonic-gate char *msg;
21710Sstevel@tonic-gate dlist_t *list;
21720Sstevel@tonic-gate } devs[2];
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate /* report bad disks and slices */
21750Sstevel@tonic-gate devs[0].msg = gettext("disks");
21760Sstevel@tonic-gate devs[0].list = bad_disks;
21770Sstevel@tonic-gate devs[1].msg = gettext("slices");
21780Sstevel@tonic-gate devs[1].list = bad_slices;
21790Sstevel@tonic-gate
21800Sstevel@tonic-gate if (bad_disks != NULL) {
21810Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
21820Sstevel@tonic-gate #if defined(sparc)
21830Sstevel@tonic-gate gettext("\n These disks are not usable, they may "
21840Sstevel@tonic-gate "may be offline or cannot be accessed:\n\n"));
21850Sstevel@tonic-gate #elif defined(i386)
21860Sstevel@tonic-gate gettext("\n These disks are not usable, they may "
21870Sstevel@tonic-gate "may be offline,\n missing a Solaris FDISK "
21880Sstevel@tonic-gate "partition or cannot be accessed:\n\n"));
21890Sstevel@tonic-gate #endif
21900Sstevel@tonic-gate print_device_list(bad_disks);
21910Sstevel@tonic-gate }
21920Sstevel@tonic-gate
21930Sstevel@tonic-gate if (bad_slices != NULL) {
21940Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, gettext(
21950Sstevel@tonic-gate "\n These slices, and subsequently the disks on which they\n"
21960Sstevel@tonic-gate "reside, are not usable, they cannot be accessed:\n\n"));
21970Sstevel@tonic-gate print_device_list(bad_slices);
21980Sstevel@tonic-gate }
21990Sstevel@tonic-gate
22000Sstevel@tonic-gate /* report used slices and usages */
22010Sstevel@tonic-gate preamble = gettext("\n These slices are not usable, %s:\n\n");
22020Sstevel@tonic-gate for (iter = used_classes; iter != NULL; iter = iter->next) {
22030Sstevel@tonic-gate slice_class_t *class = (slice_class_t *)iter->obj;
22040Sstevel@tonic-gate
22050Sstevel@tonic-gate if (class->sliceinfo != NULL) {
22060Sstevel@tonic-gate
22070Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, preamble,
22080Sstevel@tonic-gate get_slice_usage_msg(class->usage));
22090Sstevel@tonic-gate
22100Sstevel@tonic-gate slices = class->sliceinfo;
22110Sstevel@tonic-gate for (; slices != NULL; slices = slices->next) {
22120Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE, " %s\n", (char *)slices->obj);
22130Sstevel@tonic-gate }
22140Sstevel@tonic-gate }
22150Sstevel@tonic-gate }
22160Sstevel@tonic-gate
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate /*
22200Sstevel@tonic-gate * FUNCTION: char * get_slice_usage_msg(char *usage)
22210Sstevel@tonic-gate *
22220Sstevel@tonic-gate * INPUT: usage - char * string representing a slice usage classification
22230Sstevel@tonic-gate *
22240Sstevel@tonic-gate * OUTPUT: char * "friendly" usage message
22250Sstevel@tonic-gate *
22260Sstevel@tonic-gate * PURPOSE: the input usage string comes from libdiskmgt and is very terse.
22270Sstevel@tonic-gate *
22280Sstevel@tonic-gate * Convert it into a friendlier usage description suitable for user
22290Sstevel@tonic-gate * consumption.
22300Sstevel@tonic-gate */
22310Sstevel@tonic-gate static char *
get_slice_usage_msg(char * usage)22320Sstevel@tonic-gate get_slice_usage_msg(
22330Sstevel@tonic-gate char *usage)
22340Sstevel@tonic-gate {
22350Sstevel@tonic-gate char *str = NULL;
22360Sstevel@tonic-gate
22370Sstevel@tonic-gate if (string_case_compare(usage, DM_USE_MOUNT) == 0) {
22380Sstevel@tonic-gate str = gettext("they have mounted filesystems");
22390Sstevel@tonic-gate } else if (string_case_compare(usage, DM_USE_FS) == 0) {
22400Sstevel@tonic-gate str = gettext("they appear to have unmounted filesystems");
22410Sstevel@tonic-gate } else if (string_case_compare(usage, DM_USE_SVM) == 0) {
22420Sstevel@tonic-gate str = gettext("they are utilized by SVM");
22430Sstevel@tonic-gate } else if (string_case_compare(usage, DM_USE_VXVM) == 0) {
22440Sstevel@tonic-gate str = gettext("they are utilized by VxVm");
22450Sstevel@tonic-gate } else if (string_case_compare(usage, DM_USE_LU) == 0) {
22460Sstevel@tonic-gate str = gettext("they are utilized by LiveUpgrade");
22470Sstevel@tonic-gate } else if (string_case_compare(usage, DM_USE_DUMP) == 0) {
22480Sstevel@tonic-gate str = gettext("they are reserved as dump devices");
22490Sstevel@tonic-gate } else if (string_case_compare(usage, USE_DISKSET) == 0) {
22500Sstevel@tonic-gate str = gettext("they have disk set issues");
22510Sstevel@tonic-gate } else {
22520Sstevel@tonic-gate /* libdiskmgt has detected a usage unknown to layout */
22530Sstevel@tonic-gate str = usage;
22540Sstevel@tonic-gate }
22550Sstevel@tonic-gate
22560Sstevel@tonic-gate return (str);
22570Sstevel@tonic-gate }
22580Sstevel@tonic-gate
22590Sstevel@tonic-gate /*
22600Sstevel@tonic-gate * FUNCTION: set_alias(dm_descriptor_t desc, char *alias)
22610Sstevel@tonic-gate *
22620Sstevel@tonic-gate * INPUT: desc - a dm_descriptor_t handle.
22630Sstevel@tonic-gate * alias - a char * alias for the device represented
22640Sstevel@tonic-gate * by the descriptor.
22650Sstevel@tonic-gate *
22660Sstevel@tonic-gate * RETURNS: int - 0 on success
22670Sstevel@tonic-gate * !0 otherwise
22680Sstevel@tonic-gate *
22690Sstevel@tonic-gate * PURPOSE: Adds the specified alias to the known aliases for the
22700Sstevel@tonic-gate * device associated with the input descriptor.
22710Sstevel@tonic-gate */
22720Sstevel@tonic-gate int
set_alias(dm_descriptor_t desc,char * alias)22730Sstevel@tonic-gate set_alias(
22740Sstevel@tonic-gate dm_descriptor_t desc,
22750Sstevel@tonic-gate char *alias)
22760Sstevel@tonic-gate {
22770Sstevel@tonic-gate nvlist_t *attrs = NULL;
22780Sstevel@tonic-gate char **old_aliases = NULL;
22790Sstevel@tonic-gate char **new_aliases = NULL;
22800Sstevel@tonic-gate uint_t nelem = 0;
22810Sstevel@tonic-gate int error = 0;
22820Sstevel@tonic-gate int i = 0;
22830Sstevel@tonic-gate
22840Sstevel@tonic-gate if ((error = get_cached_attributes(desc, &attrs)) != 0) {
22850Sstevel@tonic-gate return (error);
22860Sstevel@tonic-gate }
22870Sstevel@tonic-gate
22880Sstevel@tonic-gate if ((error = get_string_array(
22890Sstevel@tonic-gate attrs, ATTR_DEVICE_ALIASES, &old_aliases, &nelem)) != 0) {
22900Sstevel@tonic-gate if (error != ENOENT) {
22910Sstevel@tonic-gate return (error);
22920Sstevel@tonic-gate }
22930Sstevel@tonic-gate /* no aliases yet */
22940Sstevel@tonic-gate error = 0;
22950Sstevel@tonic-gate }
22960Sstevel@tonic-gate
22970Sstevel@tonic-gate /* add new alias */
22980Sstevel@tonic-gate new_aliases = (char **)calloc(MAX_ALIASES, sizeof (char *));
22990Sstevel@tonic-gate if (new_aliases != NULL) {
23000Sstevel@tonic-gate
23010Sstevel@tonic-gate for (i = 0; i < nelem && i < MAX_ALIASES; i++) {
23020Sstevel@tonic-gate char *dup = strdup(old_aliases[i]);
23030Sstevel@tonic-gate if (dup != NULL) {
23040Sstevel@tonic-gate new_aliases[i] = dup;
23050Sstevel@tonic-gate } else {
23060Sstevel@tonic-gate error = ENOMEM;
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate }
23090Sstevel@tonic-gate
23100Sstevel@tonic-gate if (error == 0) {
23110Sstevel@tonic-gate if (i == MAX_ALIASES) {
23120Sstevel@tonic-gate volume_set_error(
23130Sstevel@tonic-gate gettext("Maximum number of device aliases "
23140Sstevel@tonic-gate "(8) reached\n"),
23150Sstevel@tonic-gate MAX_ALIASES);
23160Sstevel@tonic-gate error = -1;
23170Sstevel@tonic-gate
23180Sstevel@tonic-gate } else {
23190Sstevel@tonic-gate new_aliases[i] = alias;
23200Sstevel@tonic-gate error = set_string_array(attrs, ATTR_DEVICE_ALIASES,
23210Sstevel@tonic-gate new_aliases, i + 1);
23220Sstevel@tonic-gate }
23230Sstevel@tonic-gate }
23240Sstevel@tonic-gate
23250Sstevel@tonic-gate free(new_aliases);
23260Sstevel@tonic-gate }
23270Sstevel@tonic-gate
23280Sstevel@tonic-gate if (error == 0) {
23290Sstevel@tonic-gate /* cache descriptor under this alias */
23300Sstevel@tonic-gate error = add_cached_descriptor(alias, desc);
23310Sstevel@tonic-gate }
23320Sstevel@tonic-gate
23330Sstevel@tonic-gate return (error);
23340Sstevel@tonic-gate }
23350Sstevel@tonic-gate
23360Sstevel@tonic-gate /*
23370Sstevel@tonic-gate * FUNCTION: get_aliases(dm_descriptor_t desc, dlist_t **list)
23380Sstevel@tonic-gate *
23390Sstevel@tonic-gate * INPUT: desc - a dm_descriptor_t handle.
23400Sstevel@tonic-gate *
23410Sstevel@tonic-gate * OUTPUT: list - a dlist_t list pointing to the list of
23420Sstevel@tonic-gate * aliases associated with the device
23430Sstevel@tonic-gate * represented by the descriptor.
23440Sstevel@tonic-gate *
23450Sstevel@tonic-gate * RETURNS: int - 0 on success
23460Sstevel@tonic-gate * !0 otherwise
23470Sstevel@tonic-gate *
23480Sstevel@tonic-gate * PURPOSE: Retrieves aliases for the input descriptor and
23490Sstevel@tonic-gate * appends them to the input list.
23500Sstevel@tonic-gate *
23510Sstevel@tonic-gate * The list of returned items must be freed by calling
23520Sstevel@tonic-gate * dlist_free_items(list, free)
23530Sstevel@tonic-gate */
23540Sstevel@tonic-gate int
get_aliases(dm_descriptor_t desc,dlist_t ** list)23550Sstevel@tonic-gate get_aliases(
23560Sstevel@tonic-gate dm_descriptor_t desc,
23570Sstevel@tonic-gate dlist_t **list)
23580Sstevel@tonic-gate {
23590Sstevel@tonic-gate nvlist_t *attrs = NULL;
23600Sstevel@tonic-gate char **aliases = NULL;
23610Sstevel@tonic-gate uint_t nelem = 0;
23620Sstevel@tonic-gate int error = 0;
23630Sstevel@tonic-gate int i;
23640Sstevel@tonic-gate
23650Sstevel@tonic-gate if ((error = get_cached_attributes(desc, &attrs)) != 0) {
23660Sstevel@tonic-gate return (error);
23670Sstevel@tonic-gate }
23680Sstevel@tonic-gate
23690Sstevel@tonic-gate if ((error = get_string_array(
23700Sstevel@tonic-gate attrs, ATTR_DEVICE_ALIASES, &aliases, &nelem)) != 0) {
23710Sstevel@tonic-gate if (error == ENOENT) {
23720Sstevel@tonic-gate /* no aliases */
23730Sstevel@tonic-gate return (0);
23740Sstevel@tonic-gate }
23750Sstevel@tonic-gate }
23760Sstevel@tonic-gate
23770Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
23780Sstevel@tonic-gate dlist_t *item;
23790Sstevel@tonic-gate char *dup;
23800Sstevel@tonic-gate
23810Sstevel@tonic-gate if ((dup = strdup(aliases[i])) == NULL) {
23820Sstevel@tonic-gate error = ENOMEM;
23830Sstevel@tonic-gate break;
23840Sstevel@tonic-gate }
23850Sstevel@tonic-gate
23860Sstevel@tonic-gate if ((item = dlist_new_item(dup)) == NULL) {
23870Sstevel@tonic-gate free(dup);
23880Sstevel@tonic-gate error = ENOMEM;
23890Sstevel@tonic-gate break;
23900Sstevel@tonic-gate }
23910Sstevel@tonic-gate
23920Sstevel@tonic-gate *list = dlist_append(item, *list, AT_TAIL);
23930Sstevel@tonic-gate }
23940Sstevel@tonic-gate
23950Sstevel@tonic-gate return (error);
23960Sstevel@tonic-gate }
23970Sstevel@tonic-gate
23980Sstevel@tonic-gate /*
23990Sstevel@tonic-gate * FUNCTION: compare_start_blocks(
24000Sstevel@tonic-gate * void *obj1, void *obj2)
24010Sstevel@tonic-gate *
24020Sstevel@tonic-gate * INPUT: desc1 - opaque pointer to a dm_descriptor_t
24030Sstevel@tonic-gate * desc2 - opaque pointer to a dm_descriptor_t
24040Sstevel@tonic-gate *
24050Sstevel@tonic-gate * RETURNS: int - <0 - if desc1.stblk < desc2.stblk
24060Sstevel@tonic-gate * 0 - if desc1.stblk == desc2.stblk
24070Sstevel@tonic-gate * >0 - if desc1.stblk > desc.stblk
24080Sstevel@tonic-gate *
24090Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the start blocks of
24100Sstevel@tonic-gate * the two input dm_descriptor_t slice handles.
24110Sstevel@tonic-gate */
24120Sstevel@tonic-gate static int
compare_start_blocks(void * desc1,void * desc2)24130Sstevel@tonic-gate compare_start_blocks(
24140Sstevel@tonic-gate void *desc1,
24150Sstevel@tonic-gate void *desc2)
24160Sstevel@tonic-gate {
24170Sstevel@tonic-gate uint64_t stblk1 = 0;
24180Sstevel@tonic-gate uint64_t stblk2 = 0;
24190Sstevel@tonic-gate
24200Sstevel@tonic-gate assert(desc1 != (dm_descriptor_t)0);
24210Sstevel@tonic-gate assert(desc2 != (dm_descriptor_t)0);
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate (void) slice_get_start_block((uintptr_t)desc1, &stblk1);
24240Sstevel@tonic-gate (void) slice_get_start_block((uintptr_t)desc2, &stblk2);
24250Sstevel@tonic-gate
24260Sstevel@tonic-gate return (stblk1 - stblk2);
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate
24290Sstevel@tonic-gate /*
24300Sstevel@tonic-gate * FUNCTION: compare_desc_display_names(
24310Sstevel@tonic-gate * void *desc1, void *desc2)
24320Sstevel@tonic-gate *
24330Sstevel@tonic-gate * INPUT: desc1 - opaque pointer to a dm_descriptor_t
24340Sstevel@tonic-gate * desc2 - opaque pointer to a dm_descriptor_t
24350Sstevel@tonic-gate *
24360Sstevel@tonic-gate * RETURNS: int - <0 - if desc1.name < desc2.name
24370Sstevel@tonic-gate * 0 - if desc1.name == desc2.name
24380Sstevel@tonic-gate * >0 - if desc1.name > desc.name
24390Sstevel@tonic-gate *
24400Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the CTD names of the
24410Sstevel@tonic-gate * two input dm_descriptor_t objects.
24420Sstevel@tonic-gate */
24430Sstevel@tonic-gate static int
compare_desc_display_names(void * desc1,void * desc2)24440Sstevel@tonic-gate compare_desc_display_names(
24450Sstevel@tonic-gate void *desc1,
24460Sstevel@tonic-gate void *desc2)
24470Sstevel@tonic-gate {
24480Sstevel@tonic-gate char *name1 = NULL;
24490Sstevel@tonic-gate char *name2 = NULL;
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate assert(desc1 != (dm_descriptor_t)0);
24520Sstevel@tonic-gate assert(desc2 != (dm_descriptor_t)0);
24530Sstevel@tonic-gate
24540Sstevel@tonic-gate (void) get_display_name((uintptr_t)desc1, &name1);
24550Sstevel@tonic-gate (void) get_display_name((uintptr_t)desc2, &name2);
24560Sstevel@tonic-gate
24570Sstevel@tonic-gate return (string_case_compare(name1, name2));
24580Sstevel@tonic-gate }
2459