xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_device_util.c (revision b6c8bd52ccb0f3491c2bd1f5867985cef630564a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <sys/vtoc.h>
34 #include <sys/dktp/fdisk.h>
35 #include <errno.h>
36 #include <meta.h>
37 
38 #include <libdiskmgt.h>
39 #include "meta_repartition.h"
40 
41 #define	_LAYOUT_DEVICE_UTIL_C
42 
43 #include "volume_dlist.h"
44 #include "volume_error.h"
45 #include "volume_output.h"
46 #include "volume_nvpair.h"
47 
48 #include "layout_device_cache.h"
49 #include "layout_device_util.h"
50 #include "layout_discovery.h"
51 #include "layout_dlist_util.h"
52 #include "layout_slice.h"
53 
54 /*
55  *	Macros to produce a quoted string containing the value of a
56  *	preprocessor macro. For example, if SIZE is defined to be 256,
57  *	VAL2STR(SIZE) is "256". This is used to construct format
58  *	strings for scanf-family functions below.
59  */
60 #define	QUOTE(x)	#x
61 #define	VAL2STR(x)	QUOTE(x)
62 
63 /* private utilities for disks */
64 static int disk_get_uint64_attribute(
65 	dm_descriptor_t disk,
66 	char		*attr,
67 	uint64_t 	*val);
68 
69 static int disk_get_boolean_attribute(
70 	dm_descriptor_t	disk,
71 	char		*attr,
72 	boolean_t	*bool);
73 
74 static int disk_get_rpm(
75 	dm_descriptor_t disk,
76 	uint32_t 	*val);
77 
78 static int disk_get_sync_speed(
79 	dm_descriptor_t disk,
80 	uint32_t 	*val);
81 
82 static int disk_has_virtual_slices(
83 	dm_descriptor_t disk,
84 	boolean_t 	*bool);
85 
86 static int disk_get_virtual_slices(
87 	dm_descriptor_t disk,
88 	dlist_t 	**list);
89 
90 static int disk_get_reserved_indexes(
91 	dm_descriptor_t disk,
92 	uint16_t 	**array);
93 
94 static int disk_get_associated_desc(
95 	dm_descriptor_t	disk,
96 	dm_desc_type_t	assoc_type,
97 	char		*assoc_type_str,
98 	dlist_t		**list);
99 
100 /* utilities for slices */
101 static int slice_get_uint64_attribute(
102 	dm_descriptor_t slice,
103 	char		*attr,
104 	uint64_t 	*val);
105 
106 static int slice_set_attribute(
107 	dm_descriptor_t slice,
108 	char		*attr,
109 	uint64_t 	val);
110 
111 /*
112  * Virtual slices are created to represent slices that will be
113  * on the system after disks have been added to the destination
114  * diskset.  For the purposes of layout, these slices must
115  * look & function just as real slices that are currently on
116  * the system.
117  */
118 static dlist_t	*_virtual_slices = NULL;
119 
120 /* temporary implementation */
121 static int virtual_repartition_drive(
122 	dm_descriptor_t disk,
123 	mdvtoc_t	*vtocp);
124 
125 static int disk_add_virtual_slice(
126 	dm_descriptor_t disk,
127 	dm_descriptor_t slice);
128 
129 static int virtual_slice_get_disk(
130 	dm_descriptor_t slice,
131 	dm_descriptor_t *diskp);
132 
133 /*
134  * attribute names for layout private information stored in
135  * device nvpair attribute lists.
136  */
137 static char *ATTR_RESERVED_INDEX = "vdu_reserved_index";
138 static char *ATTR_VIRTUAL_SLICES = "vdu_virtual_slices";
139 static char *ATTR_DISK_FOR_SLICE = "vdu_disk_for_slice";
140 static char *ATTR_DEV_CTD_NAME = "vdu_device_ctd_name";
141 static char *ATTR_HBA_N_DISKS = "vdu_hba_n_usable_disks";
142 
143 /*
144  * FUNCTION:	is_ctd_like_slice_name(char *name)
145  * INPUT:	name	- a char *
146  *
147  * RETURNS:	boolean_t - B_TRUE - if name follows an alternate slice
148  *				naming scheme similar to CTD
149  *			    B_FALSE - otherwise
150  *
151  * PURPOSE:	Determines if the input name is of the form XXXsNNN
152  *		(e.g., whizzy0s1)
153  */
154 boolean_t
is_ctd_like_slice_name(char * name)155 is_ctd_like_slice_name(
156 	char *name)
157 {
158 	uint_t		s = 0;
159 	uint_t		d = 0;
160 	int		l = 0;
161 	boolean_t	is = B_FALSE;
162 
163 	/* The format strings below match and discard the non-numeric part. */
164 	if ((sscanf(name, "/dev/dsk/%*[^0-9/]%us%u%n", &d, &s, &l) == 2 ||
165 	    sscanf(name, "/dev/rdsk/%*[^0-9/]%us%u%n", &d, &s, &l) == 2 ||
166 	    sscanf(name, "%*[^0-9/]%us%u%n", &d, &s, &l) == 2) &&
167 		(l == strlen(name))) {
168 	    is = B_TRUE;
169 	}
170 
171 	return (is);
172 }
173 
174 /*
175  * FUNCTION:	is_bsd_like_slice_name(char *name)
176  * INPUT:	name	- a char *
177  *
178  * RETURNS:	boolean_t - B_TRUE - if name follows an alternate slice
179  *				BSD-like naming scheme
180  *			    B_FALSE - otherwise
181  *
182  * PURPOSE:	Determines if the input name is of the form XXXNNN[a-h]
183  *			(e.g., whizzy0a)
184  */
185 boolean_t
is_bsd_like_slice_name(char * name)186 is_bsd_like_slice_name(
187 	char *name)
188 {
189 	uint_t		d = 0;
190 	int		l = 0;
191 	boolean_t	is = B_FALSE;
192 
193 	/* The format strings below match and discard the non-numeric part. */
194 	if ((sscanf(name, "/dev/dsk/%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1 ||
195 	    sscanf(name, "/dev/rdsk/%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1 ||
196 	    sscanf(name, "%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1) &&
197 		(l == strlen(name))) {
198 	    is = B_TRUE;
199 	}
200 
201 	return (is);
202 }
203 
204 /*
205  * FUNCTION:	is_did_name(char *name)
206  * INPUT:	name	- a char *
207  *
208  * RETURNS:	boolean_t - B_TRUE - if name is from the DID namespace
209  *			    B_FALSE - otherwise
210  *
211  * PURPOSE:	Determines if the input name is from the DID namespace.
212  */
213 boolean_t
is_did_name(char * name)214 is_did_name(
215 	char *name)
216 {
217 	return (is_did_slice_name(name) || is_did_disk_name(name));
218 }
219 
220 /*
221  * FUNCTION:	is_did_slice_name(char *name)
222  * INPUT:	name	- a char *
223  *
224  * RETURNS:	boolean_t - B_TRUE - if name represents a slice from the DID
225  *					namespace
226  *			    B_FALSE - otherwise
227  *
228  * PURPOSE:	Determines if the input name is a slice from the DID namespace.
229  */
230 boolean_t
is_did_slice_name(char * name)231 is_did_slice_name(
232 	char *name)
233 {
234 	uint_t		d = 0, s = 0;
235 	int		l = 0;
236 	boolean_t	is = B_FALSE;
237 
238 	if ((sscanf(name, "/dev/did/rdsk/d%us%u%n", &d, &s, &l) == 2 ||
239 		sscanf(name, "/dev/did/dsk/d%us%u%n", &d, &s, &l) == 2 ||
240 		sscanf(name, "d%us%u%n", &d, &s, &l) == 2) ||
241 		(l == strlen(name))) {
242 	    is = B_TRUE;
243 	}
244 
245 	return (is);
246 }
247 
248 /*
249  * FUNCTION:	is_did_disk_name(char *name)
250  * INPUT:	name	- a char *
251  *
252  * RETURNS:	boolean_t - B_TRUE - if name represents a disk from the DID
253  *					namespace
254  *			    B_FALSE - otherwise
255  *
256  * PURPOSE:	Determines if the input name is a disk from the DID namespace.
257  */
258 boolean_t
is_did_disk_name(char * name)259 is_did_disk_name(
260 	char *name)
261 {
262 	uint_t		d = 0;
263 	int		l = 0;
264 	boolean_t	is = B_FALSE;
265 
266 	if ((sscanf(name, "/dev/did/rdsk/d%u%n", &d, &l) == 1 ||
267 		sscanf(name, "/dev/did/dsk/d%u%n", &d, &l) == 1 ||
268 		sscanf(name, "d%u%n", &d, &l) == 1) &&
269 		(l == strlen(name))) {
270 	    is = B_TRUE;
271 	}
272 
273 	return (is);
274 }
275 
276 /*
277  * FUNCTION:	is_ctd_name(char *name)
278  * INPUT:	name	- a char *
279  *
280  * RETURNS:	boolean_t - B_TRUE - if name is from the CTD namespace
281  *			    B_FALSE - otherwise
282  *
283  * PURPOSE:	Determines if the input name is from the CTD namespace.
284  *
285  *		{/dev/dsk/, /dev/rdsk/}cXtXdXsX
286  *		{/dev/dsk/, /dev/rdsk/}cXtXdX
287  *		{/dev/dsk/, /dev/rdsk/}cXdXsX
288  *		{/dev/dsk/, /dev/rdsk/}cXdX
289  */
290 boolean_t
is_ctd_name(char * name)291 is_ctd_name(
292 	char *name)
293 {
294 	return (is_ctd_slice_name(name) || is_ctd_disk_name(name) ||
295 		is_ctd_target_name(name) || is_ctd_ctrl_name(name));
296 }
297 
298 /*
299  * FUNCTION:	is_ctd_slice_name(char *name)
300  * INPUT:	name	- a char *
301  *
302  * RETURNS:	boolean_t - B_TRUE - if name represents a slice from the CTD
303  *				namespace
304  *			    B_FALSE - otherwise
305  *
306  * PURPOSE:	Determines if the input name is a slice name from the
307  *		CTD namespace.
308  *
309  *		{/dev/dsk/, /dev/rdsk/}cXt<WWN>dXsX
310  *		{/dev/dsk/, /dev/rdsk/}cXtXdXsX
311  *		{/dev/dsk/, /dev/rdsk/}cXdXsX
312  */
313 boolean_t
is_ctd_slice_name(char * name)314 is_ctd_slice_name(
315     char *name)
316 {
317 	uint_t		c = 0, t = 0, d = 0, s = 0;
318 	char		buf[MAXNAMELEN+1];
319 	int		l = 0;
320 	boolean_t	is = B_FALSE;
321 
322 	if ((sscanf(name, "/dev/dsk/c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 ||
323 	    sscanf(name, "/dev/rdsk/c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 ||
324 	    sscanf(name, "c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 ||
325 	    sscanf(name, "/dev/dsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
326 	    sscanf(name, "/dev/rdsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
327 	    sscanf(name, "c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
328 	    sscanf(name, "c%ud%us%u%n", &c, &d, &s, &l) == 2) &&
329 		(l == strlen(name))) {
330 	    is = B_TRUE;
331 	} else if (
332 	    (sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
333 		&c, buf, &l) == 2 ||
334 	    sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
335 		&c, buf, &l) == 2 ||
336 	    sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n",
337 		&c, buf, &l) == 2) && (l == strlen(name))) {
338 	    char *dev_pos;
339 
340 	    /* see if buf ends with "dXsX" */
341 	    if (((dev_pos = strrchr(buf, 'd')) != NULL) &&
342 		(sscanf(dev_pos, "d%us%u%n", &d, &s, &l) == 2) &&
343 		(l == strlen(dev_pos))) {
344 
345 		char wwn[MAXNAMELEN+2];
346 
347 		/* buf ends with "dXsX", truncate at the 'd' */
348 		*dev_pos = '\0';
349 
350 		/* prepend "0X" to remainder and try to scan as a hex WWN */
351 		(void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf);
352 		if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) {
353 		    is = B_TRUE;
354 		}
355 	    }
356 	}
357 
358 	return (is);
359 }
360 
361 /*
362  * FUNCTION:	is_ctd_disk_name(char *name)
363  * INPUT:	name	- a char *
364  *
365  * RETURNS:	boolean_t - B_TRUE - if name represents a disk from the CTD
366  *				namespace
367  *			    B_FALSE - otherwise
368  *
369  * PURPOSE:	Determines if the input name is a disk name from the
370  *		CTD namespace.
371  *
372  *		{/dev/dsk/, /dev/rdsk/}cXt<WWN>dX
373  *		{/dev/dsk/, /dev/rdsk/}cXtXdX
374  *		{/dev/dsk/, /dev/rdsk/}cXdX
375  */
376 boolean_t
is_ctd_disk_name(char * name)377 is_ctd_disk_name(
378     char *name)
379 {
380 	uint_t		c = 0, t = 0, d = 0;
381 	int		l = 0;
382 	char		buf[MAXNAMELEN+1];
383 	boolean_t	is = B_FALSE;
384 
385 	if ((sscanf(name, "/dev/dsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
386 	    sscanf(name, "/dev/rdsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
387 	    sscanf(name, "c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
388 	    sscanf(name, "/dev/dsk/c%ud%u%n", &c, &d, &l) == 2 ||
389 	    sscanf(name, "/dev/rdsk/c%ud%n%n", &c, &d, &l) == 2 ||
390 	    sscanf(name, "c%ud%u%n", &c, &d, &l) == 2) &&
391 		(l == strlen(name))) {
392 	    is = B_TRUE;
393 	} else if ((sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
394 	    &c, buf, &l) == 2 ||
395 	    sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
396 		&c, buf, &l) == 2 ||
397 	    sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n",
398 		&c, buf, &l) == 2) && (l == strlen(name))) {
399 	    char *dev_pos;
400 
401 	    /* see if buf ends with "dX" */
402 	    if (((dev_pos = strrchr(buf, 'd')) != NULL) &&
403 		(sscanf(dev_pos, "d%u%n", &d, &l) == 1) &&
404 		(l == strlen(dev_pos))) {
405 
406 		char wwn[MAXNAMELEN+2];
407 
408 		/* buf ends with "dX", truncate at the 'd' */
409 		*dev_pos = '\0';
410 
411 		/* prepend "0X" to remainder and try to scan as a hex WWN */
412 		(void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf);
413 		if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) {
414 		    is = B_TRUE;
415 		}
416 	    }
417 	}
418 
419 	return (is);
420 }
421 
422 /*
423  * FUNCTION:	is_ctd_disk_name(char *name)
424  * INPUT:	name	- a char *
425  *
426  * RETURNS:	boolean_t - B_TRUE - if name represents a target from the CTD
427  *				namespace
428  *			    B_FALSE - otherwise
429  *
430  * PURPOSE:	Determines if the input name is a target name from the
431  *		CTD namespace.
432  *
433  *		{/dev/dsk/, /dev/rdsk/}cXt<WWN>
434  *		{/dev/dsk/, /dev/rdsk/}cXtX
435  */
436 boolean_t
is_ctd_target_name(char * name)437 is_ctd_target_name(
438     char *name)
439 {
440 	uint_t		c = 0, t = 0;
441 	int		l = 0;
442 	char		buf[MAXNAMELEN+1];
443 	boolean_t	is = B_FALSE;
444 
445 	if ((sscanf(name, "/dev/dsk/c%ut%u%n", &c, &t, &l) == 2 ||
446 	    sscanf(name, "/dev/rdsk/c%ut%u%n", &c, &t, &l) == 2 ||
447 	    sscanf(name, "c%ut%u%n", &c, &t, &l) == 2) &&
448 		(l == strlen(name))) {
449 	    is = B_TRUE;
450 	} else if (
451 	    (sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
452 		&c, buf, &l) == 2 ||
453 	    sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
454 		&c, buf, &l) == 2 ||
455 	    sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n",
456 		&c, &buf, &l) == 2) && (l == strlen(name))) {
457 
458 	    char wwn[MAXNAMELEN+2];
459 
460 	    /* prepend "0X" to buf and try to scan as a hex WWN */
461 	    (void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf);
462 	    if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) {
463 		is = B_TRUE;
464 	    }
465 	}
466 
467 	return (is);
468 }
469 
470 /*
471  * FUNCTION:	is_ctd_ctrl_name(char *name)
472  * INPUT:	name	- a char *
473  *
474  * RETURNS:	boolean_t - B_TRUE - if name represents a controller/hba
475  *				from the CTD namespace
476  *			    B_FALSE - otherwise
477  *
478  * PURPOSE:	Determines if the input name is an HBA name from the
479  *		CTD namespace.
480  *
481  *		{/dev/dsk/, /dev/rdsk/}cX
482  */
483 boolean_t
is_ctd_ctrl_name(char * name)484 is_ctd_ctrl_name(
485 	char	*name)
486 {
487 	uint_t		c = 0;
488 	int		l = 0;
489 	boolean_t	is = B_FALSE;
490 
491 	if ((sscanf(name, "/dev/dsk/c%u%n", &c, &l) == 1 ||
492 	    sscanf(name, "/dev/rdsk/c%u%n", &c, &l) == 1 ||
493 	    sscanf(name, "c%u%n", &c, &l) == 1) &&
494 		(l == strlen(name))) {
495 	    is = B_TRUE;
496 	}
497 
498 	return (is);
499 }
500 
501 /*
502  * FUNCTION:	set_display_name(dm_descriptor_t desc, char *name)
503  *		get_display_name(dm_descriptor_t desc, char **name)
504  *
505  * INPUT:	desc	- a dm_descriptor_t handle for a device
506  *		name    - a char * name
507  *
508  * OUTPUT:	**name	- a pointer to a char * to hold the display
509  *			name associated with the input descriptor.
510  *
511  * RETURNS:	int	- 0 on success
512  *			 !0 otherwise.
513  *
514  * PURPOSE:	Helpers to set/get the input descriptor's display name.
515  *
516  *		Only slices, disks and HBAs should have display names.
517  *
518  *		The attribute is only set in the cached copy of
519  *		the device's nvpair attribute list.  This function
520  *		does not affect the underlying physical device.
521  *
522  *		An entry is added in the name->descriptor cache
523  *		so the descriptor can be found by name quickly.
524  */
525 int
set_display_name(dm_descriptor_t desc,char * name)526 set_display_name(
527 	dm_descriptor_t	desc,
528 	char		*name)
529 {
530 	nvlist_t	*attrs	= NULL;
531 	int		error	= 0;
532 
533 	((error = add_cached_descriptor(name, desc)) != 0) ||
534 	(error = get_cached_attributes(desc, &attrs)) ||
535 	(error = set_string(attrs, ATTR_DEV_CTD_NAME, name));
536 
537 	return (error);
538 }
539 
540 int
get_display_name(dm_descriptor_t desc,char ** name)541 get_display_name(
542 	dm_descriptor_t	desc,
543 	char		**name)
544 {
545 	nvlist_t	*attrs	= NULL;
546 	int		error	= 0;
547 
548 	((error = get_cached_attributes(desc, &attrs)) != 0) ||
549 	(error = get_string(attrs, ATTR_DEV_CTD_NAME, name));
550 
551 	return (error);
552 }
553 
554 /*
555  * FUNCTION:	disk_get_slices(dm_descriptor_t disk, dlist_t **list)
556  *
557  * INPUT:	disk	- a dm_descriptor_t handle for a disk
558  *
559  * OUTPUT:	*list	- a pointer to list to hold the results.
560  *
561  * RETURNS:	int	- 0 on success
562  *			 !0 otherwise.
563  *
564  * PURPOSE:	Collect all of the known slices for the input disk.
565  *
566  *		These slices may be actual slices which currently exist
567  *		on the disk, or virtual slices which will exist when the
568  *		disk is added to the destination diskset.
569  */
570 int
disk_get_slices(dm_descriptor_t disk,dlist_t ** list)571 disk_get_slices(
572 	dm_descriptor_t disk,
573 	dlist_t		**list)
574 {
575 	dm_descriptor_t	*media = NULL;
576 	boolean_t	virtual = B_FALSE;
577 	int		i = 0;
578 	int		error = 0;
579 
580 	*list = 0;
581 
582 	if ((error = disk_has_virtual_slices(disk, &virtual)) != 0) {
583 	    return (error);
584 	}
585 
586 	if (virtual == B_TRUE) {
587 	    error = disk_get_virtual_slices(disk, list);
588 	}
589 
590 	/* add real slices from disk's media... */
591 	media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
592 	(void) add_descriptors_to_free(media);
593 
594 	if (error == 0) {
595 	    /* if there's no media, this is a removeable drive */
596 	    if (media != NULL && *media != NULL) {
597 
598 		/* examine media's slices... */
599 		dm_descriptor_t	*slices = NULL;
600 		slices = dm_get_associated_descriptors(*media,
601 			DM_SLICE, &error);
602 		(void) add_descriptors_to_free(slices);
603 
604 		if (error != 0) {
605 		    print_get_assoc_desc_error(disk, gettext("slice"), error);
606 		} else {
607 		    for (i = 0; (slices[i] != NULL) && (error == 0); i++) {
608 			dlist_t *item =
609 			    dlist_new_item((void *)(uintptr_t)slices[i]);
610 			if (item == NULL) {
611 			    error = ENOMEM;
612 			} else {
613 			    *list = dlist_append(item, *list, AT_TAIL);
614 			}
615 		    }
616 		    free(slices);
617 		}
618 		free(media);
619 	    }
620 	} else {
621 	    print_get_assoc_desc_error(disk, gettext("media"), error);
622 	}
623 
624 	return (error);
625 }
626 
627 int
get_virtual_slices(dlist_t ** list)628 get_virtual_slices(
629 	dlist_t **list)
630 {
631 	*list = _virtual_slices;
632 
633 	return (0);
634 }
635 
636 /*
637  * FUNCTION:	virtual_repartition_drive(dm_descriptor_t disk,
638  *			mdvtoc_t *vtocp)
639  *
640  * INPUT:	disk	- the disk to be virtually repartitioned
641  *
642  * OUTPUT:	vtocp	- a poitner to a mdvtoc struct to hold the results
643  *
644  * RETURNS:	int	- 0 on success
645  *			 !0 otherwise.
646  *
647  * PURPOSE:	Helper which emulates the repartitioning that is done
648  *		when a disk is added to a diskset.
649  *
650  *		Modified version of meta_partition_drive which uses info
651  * 		from libdiskmgt to accomplish the repartitioning.
652  *
653  * 		This exists to allow the layout module to run with a
654  *		simulated hardware environment.
655  *
656  *		XXX This method absolutely does not produce the exact
657  *		same result as meta_repartition_drive: only information
658  *		required by the layout code is returned.  Basically,
659  *		a slice 7 (or 6 on EFI labelled disks) is created and
660  *		sized, the remained of the available cylinders are put
661  *		into slice 0.
662  *
663  *		XXX2 This method is required until there is resolution
664  *		on whether metassist testing will be done using the
665  *		hardware simulation mechanism libdiskmgt provides.
666  *		Doing so will also require parts of libmeta to be
667  *		simulated as well.  Some research has been done into
668  *		building an alternate libmeta.so containing
669  *		implementations of the functions used by metassist
670  *		that are compatible with the simulated hardware.
671  *		Actual work is currently on hold.
672  */
673 static int
virtual_repartition_drive(dm_descriptor_t disk,mdvtoc_t * vtocp)674 virtual_repartition_drive(
675 	dm_descriptor_t	disk,
676 	mdvtoc_t	*vtocp)
677 {
678 	uint_t		replicaslice = 7;
679 	unsigned long long cylsize;
680 	unsigned long long drvsize;
681 	uint_t		reservedcyl;
682 	ushort_t	resflag;
683 	unsigned long long ressize;
684 	diskaddr_t	replica_start;
685 	diskaddr_t	replica_size;
686 	diskaddr_t	data_start;
687 	diskaddr_t	data_size;
688 
689 	boolean_t	efi = B_FALSE;
690 	uint64_t	ncyls = 0;
691 	uint64_t	nheads = 0;
692 	uint64_t	nsects = 0;
693 	int		error = 0;
694 
695 	/*
696 	 * At this point, ressize is used as a minimum value.  Later it
697 	 * will be rounded up to a cylinder boundary.  ressize is in
698 	 * units of disk sectors.
699 	 */
700 	ressize = MD_DBSIZE + VTOC_SIZE;
701 	resflag = V_UNMNT;
702 
703 	((error = disk_get_is_efi(disk, &efi)) != 0) ||
704 	(error = disk_get_ncylinders(disk, &ncyls)) ||
705 	(error = disk_get_nheads(disk, &nheads)) ||
706 	(error = disk_get_nsectors(disk, &nsects));
707 	if (error != 0) {
708 	    return (error);
709 	}
710 
711 	if (efi) {
712 	    replicaslice = 6;
713 	}
714 
715 	/*
716 	 * Both cylsize and drvsize are in units of disk sectors.
717 	 *
718 	 * The intended results are of type unsigned long long.  Since
719 	 * each operand of the first multiplication is of type
720 	 * unsigned int, we risk overflow by multiplying and then
721 	 * converting the result.  Therefore we explicitly cast (at
722 	 * least) one of the operands, forcing conversion BEFORE
723 	 * multiplication, and avoiding overflow.  The second
724 	 * assignment is OK, since one of the operands is already of
725 	 * the desired type.
726 	 */
727 	cylsize = ((unsigned long long)nheads) * nsects;
728 	drvsize = cylsize * ncyls;
729 
730 	/*
731 	 * How many cylinders must we reserve for slice seven to
732 	 * ensure that it meets the previously calculated minimum
733 	 * size?
734 	 */
735 	reservedcyl = (ressize + cylsize - 1) / cylsize;
736 
737 	/*
738 	 * It seems unlikely that someone would pass us too small a
739 	 * disk, but it's still worth checking for...
740 	 */
741 	if (reservedcyl >= ncyls) {
742 	    volume_set_error(
743 		    gettext("disk is too small to hold a metadb replica"));
744 	    return (-1);
745 	}
746 
747 	replica_start = 0;
748 	replica_size = reservedcyl * cylsize;
749 	data_start = reservedcyl * cylsize;
750 	data_size = drvsize - (reservedcyl * cylsize);
751 
752 	/*
753 	 * fill in the proposed VTOC information.
754 	 */
755 
756 	/* We need at least replicaslice partitions in the proposed vtoc */
757 	vtocp->nparts = replicaslice + 1;
758 	vtocp->parts[MD_SLICE0].start = data_start;
759 	vtocp->parts[MD_SLICE0].size = data_size;
760 	vtocp->parts[MD_SLICE0].tag = V_USR;
761 	vtocp->parts[replicaslice].start = replica_start;
762 	vtocp->parts[replicaslice].size = replica_size;
763 	vtocp->parts[replicaslice].flag = resflag;
764 	vtocp->parts[replicaslice].tag = V_USR;
765 
766 	return (0);
767 }
768 
769 /*
770  * FUNCTION:	create_virtual_slices(dlist_t *disks)
771  *
772  * INPUT:	possibles - a list of dm_descriptor_t disk handles for
773  *			disks known to be available for use by layout.
774  *
775  * SIDEEFFECT:	populates the private of virtual slices.
776  *
777  * RETURNS:	int	- 0 on success
778  *			 !0 otherwise.
779  *
780  * PURPOSE:	Helper which creates virtual slices for each disk which
781  *		could be added to a diskset if necessary...
782  *
783  *		Iterate the input list of available disks and see what the
784  *		slicing would be if the disk were added to a diskset.
785  *
786  *		For the resulting slices, create virtual slice descriptors
787  *		and attributes for these slices and add them to the list of
788  *		available slices.
789  */
790 int
create_virtual_slices(dlist_t * disks)791 create_virtual_slices(
792 	dlist_t 	*disks)
793 {
794 	int		error = 0;
795 	dlist_t		*iter;
796 	boolean_t	sim = B_FALSE;
797 	static char	*simfile = "METASSISTSIMFILE";
798 
799 	sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0));
800 
801 	/* see what slices each of the disks will have when added to a set */
802 	for (iter = disks; error == 0 && iter != NULL; iter = iter->next) {
803 
804 	    dm_descriptor_t 	disk = (uintptr_t)iter->obj;
805 	    dlist_t		*slices = NULL;
806 	    mdvtoc_t		vtoc;
807 	    char		*dname;
808 	    int			i = 0;
809 
810 	    if ((error = get_display_name(disk, &dname)) != 0) {
811 		break;
812 	    }
813 
814 	    if (sim != B_TRUE) {
815 
816 		/* sim disabled: use meta_repartition_drive() */
817 
818 		md_error_t	mderror = mdnullerror;
819 		int		opts = (MD_REPART_FORCE | MD_REPART_DONT_LABEL);
820 		mdsetname_t	*sp;
821 		mddrivename_t	*dnp;
822 
823 		/* disk is in the local set */
824 		sp = metasetname(MD_LOCAL_NAME, &mderror);
825 		if (!mdisok(&mderror)) {
826 		    volume_set_error(mde_sperror(&mderror, NULL));
827 		    mdclrerror(&mderror);
828 		    error = -1;
829 		    break;
830 		}
831 
832 		dnp = metadrivename(&sp, dname, &mderror);
833 		if (!mdisok(&mderror)) {
834 		    volume_set_error(mde_sperror(&mderror, NULL));
835 		    mdclrerror(&mderror);
836 		    error = -1;
837 		    break;
838 		}
839 
840 		if (meta_repartition_drive(
841 		    sp, dnp, opts, &vtoc, &mderror) != 0) {
842 		    volume_set_error(
843 			    gettext("failed to repartition disk %s\n"),
844 			    dname);
845 		    error = -1;
846 		    break;
847 		}
848 
849 	    } else {
850 
851 		/* sim enabled: use faked repartition code */
852 		if (virtual_repartition_drive(disk, &vtoc) != 0) {
853 		    volume_set_error(
854 			    gettext("failed simulated repartition of %s\n"),
855 			    dname);
856 		    error = -1;
857 		    break;
858 		}
859 	    }
860 
861 	    /* BEGIN CSTYLED */
862 	    /*
863 	     * get the existing slices on the disk, if the repartition
864 	     * was successful, these slices need to have their size, start
865 	     * blk and size in blks set to 0
866 	     */
867 	    /* END CSTYLED */
868 	    if ((error = disk_get_slices(disk, &slices)) == 0) {
869 		dlist_t *iter2 = slices;
870 		for (; iter2 != NULL; iter2 = iter2->next) {
871 		    dm_descriptor_t sp = (uintptr_t)iter2->obj;
872 		    ((error = slice_set_start_block(sp, 0)) != 0) ||
873 		    (error = slice_set_size_in_blocks(sp, 0)) ||
874 		    (error = slice_set_size(sp, 0));
875 		}
876 		dlist_free_items(slices, NULL);
877 	    }
878 
879 	    /* scan VTOC, find slice with the free space */
880 	    for (i = 0; i < vtoc.nparts; i++) {
881 
882 		if (vtoc.parts[i].tag == V_USR &&
883 			vtoc.parts[i].flag != V_UNMNT) {
884 
885 		    /* non-replica slice with free space */
886 		    char buf[MAXPATHLEN];
887 		    (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i);
888 
889 		    if ((error = add_virtual_slice(buf,
890 			(uint32_t)i,
891 			(uint64_t)vtoc.parts[i].start,
892 			(uint64_t)vtoc.parts[i].size,
893 			disk)) != 0) {
894 			break;
895 		    }
896 
897 		} else if (vtoc.parts[i].tag == V_RESERVED) {
898 
899 		    /* skip EFI reserved slice */
900 		    continue;
901 
902 		} else if (vtoc.parts[i].tag == V_USR &&
903 			vtoc.parts[i].flag == V_UNMNT) {
904 
905 		    /* BEGIN CSTYLED */
906 		    /*
907 		     * Make the replica slice 0 sized -- this will
908 		     * force the disk to be repartitioned by
909 		     * metaset when it is added to the disk set.
910 		     *
911 		     * XXX this is a temporary workaround until
912 		     * 4712873 is integrated...
913 		     */
914 		    /* BEGIN CSTYLED */
915 		    char buf[MAXPATHLEN];
916 		    (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i);
917 		    add_slice_to_remove(buf, i);
918 
919 		    /* replica slice, stop here */
920 		    break;
921 		}
922 	    }
923 	}
924 
925 	return (error);
926 }
927 
928 /*
929  * FUNCTION:	add_virtual_slice(char *name, uint32_t index,
930  *			uint64_t startblk, uint64_t sizeblks,
931  *			dm_descriptor_t disk)
932  *
933  * INPUT:	name	- the name of the new virtual slice
934  *		index	- the VTOC index ...
935  *		startblk - the start block ...
936  *		sizeblks - the size in blocks ...
937  *		disk	- the parent disk ...
938  *
939  * RETURNS:	int	- 0 on success
940  *			 !0 otherwise.
941  *
942  * PURPOSE:	Helper which adds the appropriate data structures to
943  *		represent a new virtual slice.
944  *
945  *		allocates a new descriptor
946  *		adds entries to name->desc and desc->name caches
947  *		allocates an attribute nvpair list
948  *		fills in the relevant attributes for the slice
949  *		associates the slice with its parent disk
950  *		adds an entry to the list of all virtual slices
951  *		generates aliases if the associated disk has aliases.
952  */
953 int
add_virtual_slice(char * name,uint32_t index,uint64_t startblk,uint64_t sizeblks,dm_descriptor_t disk)954 add_virtual_slice(
955 	char		*name,
956 	uint32_t	index,
957 	uint64_t	startblk,
958 	uint64_t	sizeblks,
959 	dm_descriptor_t	disk)
960 {
961 	dm_descriptor_t sp;
962 	nvlist_t	*attrs;
963 	char		*sname;
964 	dlist_t		*aliases = NULL;
965 	dlist_t		*item = NULL;
966 	int 		error = 0;
967 
968 	if ((error = nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0)) != 0) {
969 	    return (error);
970 	}
971 
972 	/* create descriptor */
973 	((error = new_descriptor(&sp)) != 0) ||
974 	/* cache name for the descriptor */
975 	(error = add_cached_name(sp, name)) ||
976 	/* cache descriptor for the name */
977 	(error = add_cached_descriptor(name, sp)) ||
978 
979 	/* fill in attributes */
980 	(error = set_string(attrs, ATTR_DEV_CTD_NAME, name)) ||
981 	(error = set_uint32(attrs, DM_INDEX, index)) ||
982 	(error = set_uint64(attrs, DM_START, startblk)) ||
983 	(error = set_uint64(attrs, DM_SIZE, sizeblks)) ||
984 	(error = set_uint64(attrs, ATTR_DISK_FOR_SLICE, (uint64_t)disk)) ||
985 
986 	/* add attributes to the cache */
987 	(error = get_name(sp, &sname)) ||
988 	(error = add_cached_attributes(sname, attrs)) ||
989 
990 	/* connect slice to disk */
991 	(error = disk_add_virtual_slice(disk, sp)) ||
992 	(error = get_display_name(disk, &name)) ||
993 	(error = get_aliases(disk, &aliases));
994 
995 	if (error != 0) {
996 	    return (error);
997 	}
998 
999 	/* generate slice's aliases if the disk has aliases */
1000 	if (aliases != NULL) {
1001 	    char buf[MAXNAMELEN];
1002 
1003 	    for (; aliases != NULL; aliases = aliases->next) {
1004 		(void) snprintf(buf, MAXNAMELEN-1, "%ss%d",
1005 			(char *)aliases->obj, index);
1006 		error = set_alias(sp, buf);
1007 	    }
1008 	    dlist_free_items(aliases, free);
1009 	}
1010 
1011 	if ((item = dlist_new_item((void *)(uintptr_t)sp)) == NULL) {
1012 	    return (ENOMEM);
1013 	}
1014 
1015 	_virtual_slices = dlist_append(item, _virtual_slices, AT_HEAD);
1016 
1017 	oprintf(OUTPUT_DEBUG,
1018 		gettext("  created virtual slice %s start: %llu, size: %llu\n"),
1019 		sname, startblk, sizeblks);
1020 
1021 	return (error);
1022 }
1023 
1024 /*
1025  * FUNCTION:	release_virtual_slices()
1026  *
1027  * PURPOSE:	Helper which cleans up the module private list of virtual
1028  *		slices.
1029  *
1030  *		The descriptors for the virtual slices are cleaned up
1031  *		in device_cache_util.free_cached_descriptors
1032  */
1033 void
release_virtual_slices()1034 release_virtual_slices()
1035 {
1036 	dlist_free_items(_virtual_slices, NULL);
1037 	_virtual_slices = NULL;
1038 }
1039 
1040 /*
1041  * FUNCTION:	disk_add_virtual_slice(dm_descriptor_t disk,
1042  *			dm_descriptor_t slice)
1043  *
1044  * INPUT:	disk	- a dm_descriptor_t disk handle
1045  *		slice	- a dm_descriptor_t virtual slice handle
1046  *
1047  * RETURNS:	int	- 0 on success
1048  *			 !0 otherwise
1049  *
1050  * PURPOSE:	Helper which adds a virtual slice to the input disk's
1051  *		list of virtual slices.
1052  *
1053  *		The disk's virtual slice dm_descriptor_t handles are
1054  *		stored in the disk's nvpair attribute list.
1055  */
1056 static int
disk_add_virtual_slice(dm_descriptor_t disk,dm_descriptor_t slice)1057 disk_add_virtual_slice(
1058 	dm_descriptor_t	disk,
1059 	dm_descriptor_t slice)
1060 {
1061 	nvlist_t	*attrs = NULL;
1062 	uint64_t	*old_slices = NULL;
1063 	uint64_t	*new_slices = NULL;
1064 	uint_t		nelem = 0;
1065 	int		i = 0;
1066 	int		error = 0;
1067 
1068 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
1069 	    return (error);
1070 	}
1071 
1072 	if ((error = get_uint64_array(
1073 	    attrs, ATTR_VIRTUAL_SLICES, &old_slices, &nelem)) != 0) {
1074 	    if (error != ENOENT) {
1075 		return (error);
1076 	    }
1077 	    error = 0;
1078 	}
1079 
1080 	/* make a new array */
1081 	new_slices = (uint64_t *)calloc(nelem + 1, sizeof (uint64_t));
1082 	if (new_slices != NULL) {
1083 
1084 	    for (i = 0; i < nelem; i++) {
1085 		new_slices[i] = old_slices[i];
1086 	    }
1087 	    new_slices[i] = slice;
1088 
1089 	    error = set_uint64_array(
1090 		    attrs, ATTR_VIRTUAL_SLICES, new_slices, nelem);
1091 
1092 	    free(new_slices);
1093 
1094 	} else {
1095 	    error = ENOMEM;
1096 	}
1097 
1098 	return (error);
1099 }
1100 
1101 /*
1102  * FUNCTION:	disk_has_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
1103  *
1104  * INPUT:	disk	- a dm_descriptor_t disk handle
1105  *
1106  * OUTPUT:	bool	- B_TRUE - if the disk has virtual slices
1107  *			  B_FALSE - otherwise
1108  *
1109  * RETURNS:	int	- 0 on success
1110  *			 !0 otherwise
1111  *
1112  * PURPOSE:	Helper which determines if the input disk has virtual slices.
1113  *
1114  *		If a disk has virtual slices, their dm_descriptor_t handles
1115  *		will be stored in the disk's nvpair attribute list.
1116  */
1117 static int
disk_has_virtual_slices(dm_descriptor_t disk,boolean_t * bool)1118 disk_has_virtual_slices(
1119 	dm_descriptor_t	disk,
1120 	boolean_t	*bool)
1121 {
1122 	nvlist_t	*attrs = NULL;
1123 	uint64_t	*slices = NULL;
1124 	uint_t		nelem = 0;
1125 	int		error = 0;
1126 
1127 	*bool = B_FALSE;
1128 
1129 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
1130 	    return (error);
1131 	}
1132 
1133 	if ((error = get_uint64_array(
1134 	    attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) {
1135 	    if (error == ENOENT) {
1136 		error = 0;
1137 		nelem = 0;
1138 	    } else {
1139 		/* count actual number of elements */
1140 		int i = 0;
1141 		while (i < nelem) {
1142 		    if (slices[i] != -1) {
1143 			++i;
1144 		    }
1145 		}
1146 		nelem = i;
1147 	    }
1148 	}
1149 
1150 	*bool = (nelem != 0);
1151 
1152 	return (error);
1153 }
1154 
1155 /*
1156  * FUNCTION:	disk_get_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
1157  *
1158  * INPUT:	disk	- a dm_descriptor_t disk handle
1159  *
1160  * OUTPUT:	list	- a dlist_t list of dm_descriptor_t handles for the
1161  *				disk's virtual slices.
1162  *
1163  * RETURNS:	int	- 0 on success
1164  *			 !0 otherwise
1165  *
1166  * PURPOSE:	Helper which retrieves a list of the input disk's virtual
1167  *		slices.
1168  *
1169  *		If a disk has virtual slices, their dm_descriptor_t handles
1170  *		will be stored in the disk's nvpair attribute list.
1171  */
1172 static int
disk_get_virtual_slices(dm_descriptor_t disk,dlist_t ** list)1173 disk_get_virtual_slices(
1174 	dm_descriptor_t	disk,
1175 	dlist_t		**list)
1176 {
1177 	nvlist_t	*attrs = NULL;
1178 	uint64_t	*slices = NULL;
1179 	uint_t		nelem = 0;
1180 	int		error = 0;
1181 	int		i = 0;
1182 
1183 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
1184 	    return (error);
1185 	}
1186 
1187 	if ((error = get_uint64_array(
1188 	    attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) {
1189 	    if (error != ENOENT) {
1190 		return (error);
1191 	    }
1192 
1193 	    return (0);
1194 	}
1195 
1196 	for (i = 0; i < nelem && slices[i] != -1; i++) {
1197 	    dlist_t *item = NULL;
1198 
1199 	    if ((item = dlist_new_item((void*)(uintptr_t)slices[i])) == NULL) {
1200 		error = ENOMEM;
1201 		break;
1202 	    }
1203 
1204 	    *list = dlist_append(item, *list, AT_TAIL);
1205 	}
1206 
1207 	return (error);
1208 }
1209 
1210 /*
1211  * FUNCTION:	is_virtual_slice(dm_descriptor_t desc)
1212  *
1213  * INPUT:	desc	- a dm_descriptor_t handle
1214  *
1215  * RETURNS:	boolean_t - B_TRUE if the input descriptor is for
1216  *				a virtual slice.
1217  * 			B_FALSE otherwise
1218  *
1219  * PURPOSE:	Helper which determines whether the input descriptor
1220  *		corresponds to a virtual slice.
1221  *
1222  *		All virtual slices are stored in a module private list.
1223  *		This list is iterated to see if it contains the input
1224  *		descriptor.
1225  */
1226 boolean_t
is_virtual_slice(dm_descriptor_t desc)1227 is_virtual_slice(
1228 	dm_descriptor_t desc)
1229 {
1230         return (dlist_contains(_virtual_slices,
1231 			(void*)(uintptr_t)desc, compare_descriptors));
1232 }
1233 
1234 /*
1235  * FUNCTION:	disk_get_available_slice_index(dm_descriptor_t disk,
1236  *			uint32_t *newindex)
1237  *
1238  * INPUT:	disk	- a dm_descriptor_t handle for a disk
1239  *
1240  * OUTPUT:	*newindex - a pointer to a uint32_t to hold the available
1241  *			index.  If no index is available, the value pointed
1242  *			to is not modified.
1243  *
1244  * RETURNS:	int	- 0 on success
1245  *			 !0 otherwise.
1246  *
1247  * PURPOSE:	examine the input disk's list of slices and find an unused
1248  *		slice index.  The replica slice (index 7 or 6) is always
1249  *		off-limits -- it shows up as in use.  Slice 0 should only
1250  *		be used as a last resort.
1251  *
1252  *		If an available index is found, it is stored into newindex.
1253  *		Otherwise, newindex is unchanged.  This allows the caller to
1254  *		pass in an index and check if it has been modified on return.
1255  *
1256  *		V_NUMPAR is used as the number of available slices,
1257  *		SPARC systems have V_NUMPAR == 8, X86 have V_NUMPAR == 16.
1258  *
1259  *		EFI disks have only 7.
1260  */
1261 int
disk_get_available_slice_index(dm_descriptor_t disk,uint32_t * newindex)1262 disk_get_available_slice_index(
1263 	dm_descriptor_t	disk,
1264 	uint32_t	*newindex)
1265 {
1266 	dlist_t		*iter	= NULL;
1267 	dlist_t		*slices = NULL;
1268 	uint32_t	index	= 0;
1269 	uint16_t	*reserved = NULL;
1270 	boolean_t 	*used 	= NULL;
1271 	boolean_t 	is_efi	= B_FALSE;
1272 	int		error	= 0;
1273 	int		i	= 0;
1274 	int		nslices = V_NUMPAR;
1275 
1276 	if (((error = disk_get_slices(disk, &slices)) != 0) ||
1277 	    (error = disk_get_is_efi(disk, &is_efi)) != 0) {
1278 	    return (error);
1279 	}
1280 
1281 	if (is_efi == B_TRUE) {
1282 	    /* limit possible indexes to 7 for EFI */
1283 	    nslices = 7;
1284 	}
1285 
1286 	used = (boolean_t *)calloc(nslices, sizeof (boolean_t));
1287 	if (used == NULL) {
1288 	    oprintf(OUTPUT_DEBUG,
1289 		    gettext("failed allocating slice index array\n"),
1290 		    NULL);
1291 	    return (ENOMEM);
1292 	}
1293 
1294 	/* eliminate indexes that are reserved */
1295 	if ((error = disk_get_reserved_indexes(disk, &reserved)) != 0) {
1296 	    return (error);
1297 	}
1298 
1299 	if (reserved != NULL) {
1300 	    for (i = 0; i < nslices; i++) {
1301 		if (reserved[i] == 1) {
1302 		    used[i] = B_TRUE;
1303 		}
1304 	    }
1305 	}
1306 
1307 	/* eliminate slices that are in use (have a size > 0) */
1308 	/* 0 sized slices unused slices */
1309 	for (iter = slices; iter != NULL; iter = iter->next) {
1310 	    dm_descriptor_t sp = (uintptr_t)iter->obj;
1311 	    uint64_t	size = 0;
1312 
1313 	    ((error = slice_get_index(sp, &index)) != 0) ||
1314 	    (error = slice_get_size_in_blocks(sp, &size));
1315 	    if (error != 0) {
1316 		return (error);
1317 	    }
1318 
1319 	    if (size > 0) {
1320 		used[(int)index] = B_TRUE;
1321 	    }
1322 	}
1323 	dlist_free_items(slices, NULL);
1324 
1325 	for (i = 0; i < nslices; i++) {
1326 
1327 	    /* skip the index passed in */
1328 	    if (i == *newindex) {
1329 		continue;
1330 	    }
1331 
1332 	    if (used[i] != B_TRUE) {
1333 		index = i;
1334 		break;
1335 	    }
1336 	}
1337 
1338 	if (i != nslices) {
1339 	    /* return unused slice index */
1340 	    *newindex = index;
1341 	}
1342 
1343 	free((void *)used);
1344 
1345 	return (0);
1346 }
1347 
1348 /*
1349  * FUNCTION:	disk_get_media_type(dm_descriptor_t slice, uint32_t *type)
1350  *
1351  * INPUT:	slice	- a dm_descriptor_t handle for a disk
1352  *
1353  * OUTPUT:	*type	- a pointer to a uint32_t to hold the
1354  *			current type value for the media on which
1355  *			the input slice resides.
1356  *
1357  * RETURNS:	int	- 0 on success
1358  *			 !0 otherwise.
1359  *
1360  * PURPOSE:	Retrieves the media type for the disk.
1361  *
1362  *		Get the media associate with the input disk descriptor
1363  *		and determine its type.
1364  */
1365 int
disk_get_media_type(dm_descriptor_t disk,uint32_t * type)1366 disk_get_media_type(
1367 	dm_descriptor_t	disk,
1368 	uint32_t	*type)
1369 {
1370 	int		error = 0;
1371 	dm_descriptor_t	*mdp = NULL;
1372 
1373 	mdp = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1374 	(void) add_descriptors_to_free(mdp);
1375 
1376 	if (error != 0) {
1377 	    print_get_assoc_desc_error(disk, gettext("media"), error);
1378 	} else {
1379 	    /* disk should have exactly 1 media */
1380 	    if ((mdp != NULL) && (*mdp != NULL)) {
1381 		nvlist_t *attrs = dm_get_attributes(*mdp, &error);
1382 		if ((error == 0) && (attrs != NULL)) {
1383 		    error = get_uint32(attrs, DM_MTYPE, type);
1384 		}
1385 
1386 		nvlist_free(attrs);
1387 	    }
1388 	    /* no media: removeable drive */
1389 	}
1390 
1391 	if (mdp != NULL) {
1392 	    free(mdp);
1393 	}
1394 
1395 	return (error);
1396 }
1397 
1398 /*
1399  * FUNCTION:	disk_get_rpm(dm_descriptor_t disk, uint32_t *val)
1400  *		disk_get_sync_speed(dm_descriptor_t disk, uint32_t *val)
1401  *		disk_get_size_in_blocks(dm_descriptor_t disk, uint64_t *val)
1402  *		disk_get_blocksize(dm_descriptor_t disk, uint64_t *val)
1403  *		disk_get_ncylinders(dm_descriptor_t disk, uint64_t *val)
1404  *		disk_get_nheads(dm_descriptor_t disk, uint64_t *val)
1405  *		disk_get_nsectors(dm_descriptor_t disk, uint64_t *val)
1406  *		disk_get_is_efi(dm_descriptor_t disk, boolean_t *val)
1407  *		disk_get_is_online(dm_descriptor_t disk, boolean_t *val)
1408  *		disk_get_media_type(dm_descriptor_t disk, uint32_t *type)
1409  *		disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *val)
1410  *		disk_get_start_block(dm_descriptor_t disk, uint64_t *val)
1411  *
1412  * INPUT:	disk	- a dm_descriptor_t handle for a disk
1413  *
1414  * OUTPUT:	*bool	- a pointer to a variable of the appropriate
1415  *			type to hold the current value for the attribute
1416  *			of interest.
1417  *
1418  * RETURNS:	int	- 0 on success
1419  *			 !0 otherwise.
1420  *
1421  * PURPOSE:	Wrappers around disk_get_XXX_attribute that know
1422  *	        which attribute needs to be retrieved and also handle
1423  *		any necesasry type or units conversions.
1424  */
1425 static int
disk_get_rpm(dm_descriptor_t disk,uint32_t * val)1426 disk_get_rpm(
1427 	dm_descriptor_t	disk,
1428 	uint32_t	*val)
1429 {
1430 	uint64_t	val64 = 0;
1431 	int		error = 0;
1432 
1433 	if ((error = disk_get_uint64_attribute(
1434 	    disk, DM_RPM, &val64)) != 0) {
1435 	    return (error);
1436 	}
1437 
1438 	*val = (uint32_t)val64;
1439 
1440 	return (error);
1441 }
1442 
1443 int
disk_get_drive_type(dm_descriptor_t disk,uint32_t * val)1444 disk_get_drive_type(
1445 	dm_descriptor_t	disk,
1446 	uint32_t	*val)
1447 {
1448 	uint64_t	val64 = 0;
1449 	int		error = 0;
1450 
1451 	if ((error = disk_get_uint64_attribute(
1452 	    disk, DM_DRVTYPE, &val64)) != 0) {
1453 	    return (error);
1454 	}
1455 
1456 	*val = (uint32_t)val64;
1457 
1458 	return (error);
1459 }
1460 
1461 static int
disk_get_sync_speed(dm_descriptor_t disk,uint32_t * val)1462 disk_get_sync_speed(
1463 	dm_descriptor_t	disk,
1464 	uint32_t	*val)
1465 {
1466 	uint64_t	val64 = 0;
1467 	int		error = 0;
1468 
1469 	if ((error = disk_get_uint64_attribute(
1470 	    disk, DM_SYNC_SPEED, &val64)) != 0) {
1471 	    return (error);
1472 	}
1473 
1474 	*val = (uint32_t)val64;
1475 
1476 	return (error);
1477 }
1478 
1479 /* returns number of usable blocks */
1480 int
disk_get_size_in_blocks(dm_descriptor_t disk,uint64_t * val)1481 disk_get_size_in_blocks(
1482 	dm_descriptor_t	disk,
1483 	uint64_t	*val)
1484 {
1485 	return (disk_get_uint64_attribute(disk, DM_NACCESSIBLE, val));
1486 }
1487 
1488 /* returns first usable block on disk */
1489 int
disk_get_start_block(dm_descriptor_t disk,uint64_t * val)1490 disk_get_start_block(
1491 	dm_descriptor_t	disk,
1492 	uint64_t	*val)
1493 {
1494 	return (disk_get_uint64_attribute(disk, DM_START, val));
1495 }
1496 
1497 int
disk_get_blocksize(dm_descriptor_t disk,uint64_t * val)1498 disk_get_blocksize(
1499 	dm_descriptor_t	disk,
1500 	uint64_t	*val)
1501 {
1502 	return (disk_get_uint64_attribute(disk, DM_BLOCKSIZE, val));
1503 }
1504 
1505 int
disk_get_ncylinders(dm_descriptor_t disk,uint64_t * val)1506 disk_get_ncylinders(
1507 	dm_descriptor_t	disk,
1508 	uint64_t	*val)
1509 {
1510 	return (disk_get_uint64_attribute(disk, DM_NCYLINDERS, val));
1511 }
1512 
1513 int
disk_get_nheads(dm_descriptor_t disk,uint64_t * val)1514 disk_get_nheads(
1515 	dm_descriptor_t	disk,
1516 	uint64_t	*val)
1517 {
1518 	return (disk_get_uint64_attribute(disk, DM_NHEADS, val));
1519 }
1520 
1521 int
disk_get_nsectors(dm_descriptor_t disk,uint64_t * val)1522 disk_get_nsectors(
1523 	dm_descriptor_t	disk,
1524 	uint64_t	*val)
1525 {
1526 	return (disk_get_uint64_attribute(disk, DM_NSECTORS, val));
1527 }
1528 
1529 /*
1530  * FUNCTION:	disk_get_is_online(dm_descriptor_t disk, boolean_t *val)
1531  *
1532  * INPUT:	disk	- a dm_descriptor_t handle for a disk
1533  *
1534  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
1535  *
1536  * RETURNS:	int	- 0 on success
1537  *			 !0 otherwise.
1538  *
1539  * PURPOSE:	Determine if the input disk is "online".
1540  *
1541  *		Check the status bit of the drive, if it is 1 the drive
1542  *		is online, if it is 0 the drive is offline.
1543  */
1544 int
disk_get_is_online(dm_descriptor_t disk,boolean_t * val)1545 disk_get_is_online(
1546 	dm_descriptor_t	disk,
1547 	boolean_t	*val)
1548 {
1549 	uint64_t	status = 0;
1550 	int		error = 0;
1551 
1552 	*val = B_FALSE;
1553 
1554 	error = disk_get_uint64_attribute(disk, DM_STATUS, &status);
1555 	if (error == 0) {
1556 	    *val = (status == 1) ? B_TRUE : B_FALSE;
1557 	}
1558 
1559 	return (error);
1560 }
1561 
1562 /*
1563  * FUNCTION:	disk_get_is_efi(dm_descriptor_t disk, boolean_t *bool)
1564  *
1565  * INPUT:	disk	- a dm_descriptor_t handle for a disk
1566  *
1567  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
1568  *
1569  * RETURNS:	int	- 0 on success
1570  *			 !0 otherwise.
1571  *
1572  * PURPOSE:	Determine if the input disk is labeled with an EFI label.
1573  *
1574  *		The label type is actually a property of the media
1575  *		associated with the disk, so retrieve the media and
1576  *		check if it is EFI labeled.
1577  */
1578 int
disk_get_is_efi(dm_descriptor_t disk,boolean_t * bool)1579 disk_get_is_efi(
1580 	dm_descriptor_t	disk,
1581 	boolean_t	*bool)
1582 {
1583 	return (disk_get_boolean_attribute(disk, DM_EFI, bool));
1584 }
1585 
1586 /*
1587  * FUNCTION:	disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *bool)
1588  *
1589  * INPUT:	disk	- a dm_descriptor_t handle for a disk
1590  *
1591  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
1592  *
1593  * RETURNS:	int	- 0 on success
1594  *			 !0 otherwise.
1595  *
1596  * PURPOSE:	Determine if the input disk has an FDISK partition.
1597  */
1598 int
disk_get_has_fdisk(dm_descriptor_t disk,boolean_t * bool)1599 disk_get_has_fdisk(
1600 	dm_descriptor_t	disk,
1601 	boolean_t	*bool)
1602 {
1603 	return (disk_get_boolean_attribute(disk, DM_FDISK, bool));
1604 }
1605 
1606 /*
1607  * FUNCTION:	disk_get_has_solaris_partition(dm_descriptor_t disk, boolean_t *bool)
1608  *
1609  * INPUT:	disk	- a dm_descriptor_t handle for a disk
1610  *
1611  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
1612  *
1613  * RETURNS:	int	- 0 on success
1614  *			 !0 otherwise.
1615  *
1616  * PURPOSE:	Determine if the input disk has a Solaris FDISK partition.
1617  */
1618 int
disk_get_has_solaris_partition(dm_descriptor_t disk,boolean_t * bool)1619 disk_get_has_solaris_partition(
1620 	dm_descriptor_t	disk,
1621 	boolean_t	*bool)
1622 {
1623 	boolean_t	has_fdisk = B_FALSE;
1624 	int		error = 0;
1625 
1626 	if ((error = disk_get_has_fdisk(disk, &has_fdisk)) != 0) {
1627 	    return (error);
1628 	}
1629 
1630 	*bool = B_FALSE;
1631 
1632 	if (has_fdisk == B_TRUE) {
1633 	    /* get disk's media */
1634 	    dm_descriptor_t *media;
1635 	    media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1636 	    (void) add_descriptors_to_free(media);
1637 	    if (error != 0) {
1638 		print_get_assoc_desc_error(disk, gettext("media"), error);
1639 	    } else if ((media != NULL) && (*media != NULL)) {
1640 		/* get media's partitions */
1641 		dm_descriptor_t *parts;
1642 		parts = dm_get_associated_descriptors(
1643 			media[0], DM_PARTITION, &error);
1644 		(void) add_descriptors_to_free(parts);
1645 		if (error != 0) {
1646 		    print_get_assoc_desc_error(media[0],
1647 			    gettext("partitions"), error);
1648 		} else {
1649 		    /* search partitions for one with type Solaris */
1650 		    int i = 0;
1651 		    for (; (parts != NULL) && (parts[i] != NULL) &&
1652 			(error == 0) && (*bool == B_FALSE); i++) {
1653 			nvlist_t *attrs = dm_get_attributes(parts[i], &error);
1654 			uint32_t ptype = 0;
1655 			if ((error == 0) && (attrs != NULL)) {
1656 			    error = get_uint32(attrs, DM_PTYPE, &ptype);
1657 			    if ((error == 0) &&
1658 			        (ptype == SUNIXOS || ptype == SUNIXOS2)) {
1659 				    *bool = B_TRUE;
1660 			    }
1661 			}
1662 			nvlist_free(attrs);
1663 		    }
1664 		}
1665 
1666 		free(parts);
1667 		free(media);
1668 	    }
1669 
1670 	    /* if there was no media, it was a removeable drive */
1671 	}
1672 
1673 	return (error);
1674 }
1675 
1676 static int
disk_get_boolean_attribute(dm_descriptor_t disk,char * attr,boolean_t * bool)1677 disk_get_boolean_attribute(
1678 	dm_descriptor_t	disk,
1679 	char		*attr,
1680 	boolean_t	*bool)
1681 {
1682 	nvlist_t	*attrs	= NULL;
1683 	int		error	= 0;
1684 
1685 	*bool = B_FALSE;
1686 
1687 	if ((strcmp(attr, DM_EFI) == 0) ||
1688 	    (strcmp(attr, DM_FDISK) == 0)) {
1689 
1690 	    /*
1691 	     * these attributes are actually on the media,
1692 	     * not the disk... so get the media descriptor
1693 	     * for this disk
1694 	     */
1695 	    dm_descriptor_t *media;
1696 
1697 	    media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1698 	    (void) add_descriptors_to_free(media);
1699 
1700 	    if (error != 0) {
1701 		print_get_assoc_desc_error(disk, gettext("media"), error);
1702 	    } else if ((media != NULL) && (*media != NULL)) {
1703 		/* if there's no media, it is a removeable drive */
1704 		error = get_cached_attributes(media[0], &attrs);
1705 	    }
1706 	    free(media);
1707 
1708 	} else {
1709 	    error = get_cached_attributes(disk, &attrs);
1710 	    if (error != 0) {
1711 		print_get_desc_attr_error(disk, gettext("drive"), attr, error);
1712 	    }
1713 	}
1714 
1715 	if (error != 0) {
1716 	    return (error);
1717 	}
1718 
1719 	if (nvlist_lookup_boolean(attrs, attr) == 0) {
1720 	    *bool = B_TRUE;
1721 	}
1722 
1723 	return (error);
1724 }
1725 
1726 static int
disk_get_uint64_attribute(dm_descriptor_t disk,char * attr,uint64_t * val)1727 disk_get_uint64_attribute(
1728 	dm_descriptor_t	disk,
1729 	char		*attr,
1730 	uint64_t	*val)
1731 {
1732 	nvlist_t	*attrs	= NULL;
1733 	uint32_t	ui32	= 0;
1734 	int		error	= 0;
1735 
1736 	/*
1737 	 * these attributes are actually on the media,
1738 	 * not the disk... so get the media descriptor
1739 	 * for this disk
1740 	 */
1741 	if ((strcmp(attr, DM_SIZE) == 0) ||
1742 	    (strcmp(attr, DM_START) == 0) ||
1743 	    (strcmp(attr, DM_NACCESSIBLE) == 0) ||
1744 	    (strcmp(attr, DM_BLOCKSIZE) == 0) ||
1745 	    (strcmp(attr, DM_NCYLINDERS) == 0) ||
1746 	    (strcmp(attr, DM_NHEADS) == 0) ||
1747 	    (strcmp(attr, DM_NSECTORS) == 0)) {
1748 
1749 	    dm_descriptor_t *media;
1750 
1751 	    media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1752 	    (void) add_descriptors_to_free(media);
1753 
1754 	    if (error != 0) {
1755 		print_get_assoc_desc_error(disk, gettext("media"), error);
1756 	    } else if ((media == NULL) || (*media == NULL)) {
1757 		print_get_assoc_desc_error(disk, gettext("media"), error);
1758 		error = -1;
1759 	    } else {
1760 		error = get_cached_attributes(media[0], &attrs);
1761 		free(media);
1762 	    }
1763 
1764 	} else {
1765 	    error = get_cached_attributes(disk, &attrs);
1766 	    if (error != 0) {
1767 		print_get_desc_attr_error(disk, gettext("drive"), attr, error);
1768 	    }
1769 	}
1770 
1771 	if (error != 0) {
1772 	    return (error);
1773 	}
1774 
1775 	if (strcmp(attr, DM_SIZE) == 0 ||
1776 	    strcmp(attr, DM_NACCESSIBLE) == 0 ||
1777 	    strcmp(attr, DM_START) == 0) {
1778 	    error = get_uint64(attrs, attr, val);
1779 	} else if (strcmp(attr, DM_BLOCKSIZE) == 0 ||
1780 	    strcmp(attr, DM_NCYLINDERS) == 0 ||
1781 	    strcmp(attr, DM_NHEADS) == 0 ||
1782 	    strcmp(attr, DM_NSECTORS) == 0 ||
1783 	    strcmp(attr, DM_RPM) == 0 ||
1784 	    strcmp(attr, DM_DRVTYPE) == 0 ||
1785 	    strcmp(attr, DM_SYNC_SPEED) == 0 ||
1786 	    strcmp(attr, DM_STATUS) == 0) {
1787 	    error = get_uint32(attrs, attr, &ui32);
1788 	    *val = (uint64_t)ui32;
1789 	}
1790 
1791 	return (error);
1792 }
1793 
1794 /*
1795  * FUNCTION:	group_similar_hbas(dlist_t *hbas, dlist_t **list)
1796  *
1797  * INPUT:	hbas	- a list of HBA dm_descriptor_t handles.
1798  *
1799  * OUTPUT:	**list	- a pointer to a list to hold the lists of HBAs
1800  *			grouped by characteristics.
1801  *
1802  * RETURNS:	int	- 0 on success
1803  *			 !0 otherwise.
1804  *
1805  * PURPOSE:	Examine the input HBAs and collate them into separate
1806  *		lists, grouped by their type and the protocols they
1807  *		support.
1808  *
1809  *		The returned list of list is arranged in decreasing order
1810  *		of preference, "better" HBAs come first.
1811  *
1812  *		find all MPXIO controllers
1813  *		find all similar FC HBAs
1814  *		find all similar SCSI HBAs
1815  *		    fast{wide}80
1816  *		    fast{wide}40
1817  *		    fast{wide}20
1818  *		    clock         uint32  ??
1819  *		find all similar ATA/IDE HBAs
1820  *		find all similar USB HBAs
1821  */
1822 int
group_similar_hbas(dlist_t * hbas,dlist_t ** list)1823 group_similar_hbas(
1824 	dlist_t	*hbas,
1825 	dlist_t **list)
1826 {
1827 	/* preference order of HBAs */
1828 	enum {
1829 		HBA_FIBRE_MPXIO = 0,
1830 		HBA_SCSI_MPXIO,
1831 		HBA_FIBRE,
1832 		HBA_SCSI_FW80,
1833 		HBA_SCSI_FW40,
1834 		HBA_SCSI_FW20,
1835 		HBA_SCSI_F80,
1836 		HBA_SCSI_F40,
1837 		HBA_SCSI_F20,
1838 		HBA_SCSI,
1839 		HBA_ATA,
1840 		HBA_USB,
1841 		HBA_LAST
1842 	};
1843 
1844 	dlist_t		*groups	= NULL;
1845 	dlist_t		*iter = NULL;
1846 	dlist_t		*item = NULL;
1847 	dlist_t		*lists[HBA_LAST];
1848 
1849 	int		error = 0;
1850 	int		i = 0;
1851 
1852 	(void) memset(lists, '\0', HBA_LAST * sizeof (dlist_t *));
1853 
1854 	for (iter = hbas;
1855 	    (iter != NULL) && (error == 0);
1856 	    iter = iter->next) {
1857 
1858 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
1859 	    char	*type = NULL;
1860 
1861 	    /* if item doesn't go into a list it must be freed */
1862 	    if ((item = dlist_new_item((void *)(uintptr_t)hba)) == NULL) {
1863 		error = ENOMEM;
1864 		continue;
1865 	    }
1866 
1867 	    if ((error = hba_get_type(hba, &type)) != 0) {
1868 		free(item);
1869 		continue;
1870 	    }
1871 
1872 	    if (strcmp(type, DM_CTYPE_FIBRE) == 0) {
1873 
1874 		boolean_t	ismpxio = B_FALSE;
1875 
1876 		if ((error = hba_is_multiplex(hba, &ismpxio)) == 0) {
1877 		    if (ismpxio) {
1878 			lists[HBA_FIBRE_MPXIO] =
1879 			    dlist_append(item,
1880 				    lists[HBA_FIBRE_MPXIO], AT_TAIL);
1881 		    } else {
1882 			lists[HBA_FIBRE] =
1883 			    dlist_append(item,
1884 				    lists[HBA_FIBRE], AT_TAIL);
1885 		    }
1886 		} else {
1887 		    free(item);
1888 		}
1889 
1890 	    } else if (strcmp(type, DM_CTYPE_SCSI) == 0) {
1891 
1892 		/* determine subtype */
1893 		boolean_t	iswide = B_FALSE;
1894 		boolean_t	ismpxio = B_FALSE;
1895 		boolean_t	is80 = B_FALSE;
1896 		boolean_t	is40 = B_FALSE;
1897 		boolean_t	is20 = B_FALSE;
1898 
1899 		((error = hba_supports_wide(hba, &iswide)) != 0) ||
1900 		(error = hba_is_multiplex(hba, &ismpxio)) ||
1901 		(error = hba_is_fast_80(hba, &is80)) ||
1902 		(error = hba_is_fast_40(hba, &is40)) ||
1903 		(error = hba_is_fast_20(hba, &is20));
1904 
1905 		if (error == 0) {
1906 
1907 		    if (ismpxio) {
1908 
1909 			lists[HBA_SCSI_MPXIO] =
1910 			    dlist_append(item,
1911 				    lists[HBA_SCSI_MPXIO], AT_TAIL);
1912 
1913 		    } else if (is80) {
1914 
1915 			if (iswide) {
1916 			    lists[HBA_SCSI_FW80] =
1917 				dlist_append(item,
1918 					lists[HBA_SCSI_FW80], AT_TAIL);
1919 			} else {
1920 			    lists[HBA_SCSI_F80] =
1921 				dlist_append(item,
1922 					lists[HBA_SCSI_F80], AT_TAIL);
1923 			}
1924 
1925 		    } else if (is40) {
1926 
1927 			if (iswide) {
1928 			    lists[HBA_SCSI_FW40] =
1929 				dlist_append(item,
1930 					lists[HBA_SCSI_FW40], AT_TAIL);
1931 			} else {
1932 			    lists[HBA_SCSI_F40] =
1933 				dlist_append(item,
1934 					lists[HBA_SCSI_F40], AT_TAIL);
1935 			}
1936 
1937 		    } else if (is20) {
1938 
1939 			if (iswide) {
1940 			    lists[HBA_SCSI_FW20] =
1941 				dlist_append(item,
1942 					lists[HBA_SCSI_FW20], AT_TAIL);
1943 			} else {
1944 			    lists[HBA_SCSI_F20] =
1945 				dlist_append(item,
1946 					lists[HBA_SCSI_F20], AT_TAIL);
1947 			}
1948 
1949 		    } else {
1950 			lists[HBA_SCSI] =
1951 			    dlist_append(item, lists[HBA_SCSI], AT_TAIL);
1952 		    }
1953 
1954 		} else {
1955 		    free(item);
1956 		}
1957 
1958 	    } else if (strcmp(type, DM_CTYPE_ATA) == 0) {
1959 		lists[HBA_ATA] =
1960 		    dlist_append(item, lists[HBA_ATA], AT_TAIL);
1961 	    } else if (strcmp(type, DM_CTYPE_USB) == 0) {
1962 		lists[HBA_USB] =
1963 		    dlist_append(item, lists[HBA_USB], AT_TAIL);
1964 	    } else if (strcmp(type, DM_CTYPE_UNKNOWN) == 0) {
1965 		oprintf(OUTPUT_DEBUG,
1966 			gettext("found an HBA with unknown type\n"));
1967 		free(item);
1968 	    }
1969 	}
1970 
1971 	if (error == 0) {
1972 	    /* collect individual lists into a list of lists */
1973 	    for (i = 0; (i < HBA_LAST) && (error == 0); i++) {
1974 		if (lists[i] != NULL) {
1975 		    if ((item = dlist_new_item(lists[i])) == NULL) {
1976 			error = ENOMEM;
1977 		    } else {
1978 			groups = dlist_append(item, groups, AT_TAIL);
1979 		    }
1980 		}
1981 	    }
1982 	}
1983 
1984 	if (error != 0) {
1985 	    for (i = 0; i < HBA_LAST; i++) {
1986 		dlist_free_items(lists[i], NULL);
1987 		lists[i] = NULL;
1988 	    }
1989 
1990 	    if (groups != NULL) {
1991 		dlist_free_items(groups, NULL);
1992 	    }
1993 	}
1994 
1995 	*list = groups;
1996 
1997 	return (error);
1998 }
1999 
2000 /*
2001  * FUNCTION:	hba_group_usable_disks(dm_descriptor_t hba, dlist_t **list)
2002  *
2003  * INPUT:	hba	- a dm_descriptor_t handle for a slice
2004  *
2005  * OUTPUT:	**list	- a pointer to a list to hold the lists of disks
2006  *			grouped by characteristics.
2007  *
2008  * RETURNS:	int	- 0 on success
2009  *			 !0 otherwise.
2010  *
2011  * PURPOSE:	Examine the disks assocated with the HBA and collates them
2012  *		into separate lists, grouped by similar characteristics.
2013  *
2014  *		get disks on HBA
2015  *		check disks against _usable_disks list
2016  *		group disks by similarities:
2017  *			sync-speed    uint32
2018  *			wide          boolean
2019  *			rpm           uint32
2020  *
2021  *		XXX this function is currently unused.  At some point,
2022  *		it may be useful to group disks by performance
2023  *		characteristics and use "better" disks before others.
2024  */
2025 int
hba_group_usable_disks(dm_descriptor_t hba,dlist_t ** list)2026 hba_group_usable_disks(
2027 	dm_descriptor_t	hba,
2028 	dlist_t		**list)
2029 {
2030 	dm_descriptor_t *disk = NULL;
2031 	char 		*name = NULL;
2032 	int		i = 0;
2033 	int		error = 0;
2034 
2035 	disk = dm_get_associated_descriptors(hba, DM_DRIVE, &error);
2036 	(void) add_descriptors_to_free(disk);
2037 
2038 	if (error != 0) {
2039 	    print_get_assoc_desc_error(hba, gettext("drive"), error);
2040 	    return (error);
2041 	} else if ((disk == NULL) || (*disk == NULL)) {
2042 	    print_get_assoc_desc_error(hba, gettext("drive"), error);
2043 	    error = -1;
2044 	}
2045 
2046 	for (i = 0; (disk[i] != NULL) && (error == 0); i++) {
2047 
2048 	    uint32_t dtype = DM_DT_UNKNOWN;
2049 	    dlist_t *usable = NULL;
2050 
2051 	    /* ignore non fixed media drives */
2052 	    if (((error = disk_get_drive_type(disk[i], &dtype)) != 0) ||
2053 		(dtype != DM_DT_FIXED)) {
2054 		continue;
2055 	    }
2056 
2057 	    if (dlist_contains(usable, &disk[i],
2058 		compare_descriptor_names) == B_TRUE) {
2059 
2060 		uint64_t bsize	= 0;
2061 		uint64_t ncyls	= 0;
2062 		uint64_t nsects	= 0;
2063 		uint64_t nheads	= 0;
2064 		uint32_t rpm	= 0;
2065 		uint32_t sync	= 0;
2066 
2067 		name = NULL;
2068 		((error = get_display_name(disk[i], &name)) != 0) ||
2069 		(error = disk_get_blocksize(disk[i], &bsize)) ||
2070 		(error = disk_get_nheads(disk[i], &nheads)) ||
2071 		(error = disk_get_nsectors(disk[i], &nsects)) ||
2072 		(error = disk_get_ncylinders(disk[i], &ncyls)) ||
2073 		(error = disk_get_rpm(disk[i], &rpm)) ||
2074 		(error = disk_get_sync_speed(disk[i], &sync));
2075 		if (error != 0) {
2076 		    continue;
2077 		}
2078 
2079 		oprintf(OUTPUT_VERBOSE,
2080 			gettext("found an available disk: %s\n\t"
2081 			"sync_speed = %u, rpm = %u, "
2082 			"nsect = %llu, blksiz = %llu\n"),
2083 			name, sync, rpm, nsects, bsize);
2084 
2085 		/* add to the appropriate list */
2086 	    }
2087 	}
2088 
2089 	if (disk != NULL) {
2090 	    free(disk);
2091 	}
2092 
2093 	return (error);
2094 }
2095 
2096 /*
2097  * FUNCTION:	hba_get_n_avail_disks(dm_descriptor_t hba, uint16_t *val)
2098  *		hba_set_n_avail_disks(dm_descriptor_t hba, uint16_t val)
2099  *
2100  * INPUT:	hba	- a dm_descriptor_t handle for a slice
2101  *
2102  * OUTPUT:	*val	- a pointer to a uint16_t to hold the current number
2103  *				of available disks for the input HBA.
2104  *
2105  * RETURNS:	int	- 0 on success
2106  *			 !0 otherwise.
2107  */
2108 int
hba_set_n_avail_disks(dm_descriptor_t hba,uint16_t val)2109 hba_set_n_avail_disks(
2110 	dm_descriptor_t	hba,
2111 	uint16_t	val)
2112 {
2113 	nvlist_t	*attrs;
2114 	int		error = 0;
2115 
2116 	((error = get_cached_attributes(hba, &attrs)) != 0) ||
2117 	(error = set_uint16(attrs, ATTR_HBA_N_DISKS, val));
2118 
2119 	return (error);
2120 }
2121 
2122 int
hba_get_n_avail_disks(dm_descriptor_t hba,uint16_t * val)2123 hba_get_n_avail_disks(
2124 	dm_descriptor_t	hba,
2125 	uint16_t	*val)
2126 {
2127 	nvlist_t	*attrs;
2128 	int		error = 0;
2129 
2130 	*val = 0;
2131 
2132 	((error = get_cached_attributes(hba, &attrs)) != 0) ||
2133 	(error = get_uint16(attrs, ATTR_HBA_N_DISKS, val));
2134 
2135 	return (error);
2136 }
2137 
2138 /*
2139  * FUNCTION:	hba_get_type(dm_descriptor_t hba, char **type)
2140  *
2141  * INPUT:	hba	- a dm_descriptor_t handle for a HBA
2142  *
2143  * OUTPUT:	**type	- a char * to hold the current type value for
2144  *			the HBA.
2145  *
2146  * RETURNS:	int	- 0 on success
2147  *			 !0 otherwise.
2148  *
2149  * PURPOSE:	Retrieves the type attribute for the HBA.
2150  */
2151 int
hba_get_type(dm_descriptor_t hba,char ** type)2152 hba_get_type(
2153 	dm_descriptor_t	hba,
2154 	char		**type)
2155 {
2156 	nvlist_t	*attrs;
2157 	int		error = 0;
2158 
2159 	*type = NULL;
2160 
2161 	((error = get_cached_attributes(hba, &attrs)) != 0) ||
2162 	(error = get_string(attrs, DM_CTYPE, type));
2163 
2164 	return (error);
2165 }
2166 
2167 /*
2168  * FUNCTION:	hba_is_fast(dm_descriptor_t hba, boolean_t *bool)
2169  *		hba_is_fast20(dm_descriptor_t hba, boolean_t *bool)
2170  *		hba_is_fast40(dm_descriptor_t hba, boolean_t *bool)
2171  *		hba_is_fast80(dm_descriptor_t hba, boolean_t *bool)
2172  *		hba_is_multiplex(dm_descriptor_t hba, boolean_t *bool)
2173  *		hba_is_wide(dm_descriptor_t hba, boolean_t *bool)
2174  *
2175  * INPUT:	hba	- a dm_descriptor_t handle for a HBA
2176  *
2177  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the
2178  *			boolean value of the predicate.
2179  *
2180  * RETURNS:	int	- 0 on success
2181  *			 !0 otherwise.
2182  *
2183  * PURPOSE:	Wrappers around hba_supports_protocol which determines
2184  *		if the input HBA supports the protocol of interest.
2185  */
2186 int
hba_is_fast(dm_descriptor_t hba,boolean_t * bool)2187 hba_is_fast(
2188 	dm_descriptor_t	hba,
2189 	boolean_t	*bool)
2190 {
2191 	return (hba_supports_protocol(hba, DM_FAST, bool));
2192 }
2193 
2194 int
hba_is_fast_20(dm_descriptor_t hba,boolean_t * bool)2195 hba_is_fast_20(
2196 	dm_descriptor_t	hba,
2197 	boolean_t	*bool)
2198 {
2199 	return (hba_supports_protocol(hba, DM_FAST20, bool));
2200 }
2201 
2202 int
hba_is_fast_40(dm_descriptor_t hba,boolean_t * bool)2203 hba_is_fast_40(
2204 	dm_descriptor_t	hba,
2205 	boolean_t	*bool)
2206 {
2207 	return (hba_supports_protocol(hba, DM_FAST40, bool));
2208 }
2209 
2210 int
hba_is_fast_80(dm_descriptor_t hba,boolean_t * bool)2211 hba_is_fast_80(
2212 	dm_descriptor_t	hba,
2213 	boolean_t	*bool)
2214 {
2215 	return (hba_supports_protocol(hba, DM_FAST80, bool));
2216 }
2217 
2218 int
hba_is_multiplex(dm_descriptor_t hba,boolean_t * bool)2219 hba_is_multiplex(
2220 	dm_descriptor_t	hba,
2221 	boolean_t	*bool)
2222 {
2223 	return (hba_supports_protocol(hba, DM_MULTIPLEX, bool));
2224 }
2225 
2226 int
hba_supports_wide(dm_descriptor_t hba,boolean_t * bool)2227 hba_supports_wide(
2228 	dm_descriptor_t	hba,
2229 	boolean_t	*bool)
2230 {
2231 	nvlist_t	*attrs	= NULL;
2232 	int		error	= 0;
2233 
2234 	*bool = B_FALSE;
2235 
2236 	if ((error = get_cached_attributes(hba, &attrs)) != 0) {
2237 	    return (error);
2238 	}
2239 
2240 	*bool = (0 == nvlist_lookup_boolean(attrs, DM_WIDE));
2241 
2242 	return (error);
2243 }
2244 
2245 /*
2246  * FUNCTION:	hba_supports_protocol(dm_descriptor_t hba, char *attr,
2247  *			boolean_t *bool)
2248  *
2249  * INPUT:	hba	- a dm_descriptor_t handle for a HBA
2250  *		attr	- a protocol "name"
2251  *
2252  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the
2253  *			boolean value of the predicate.
2254  *
2255  * RETURNS:	int	- 0 on success
2256  *			 !0 otherwise.
2257  *
2258  * PURPOSE:	Checks the HBAs attributes to see if it is known to
2259  *		support the protocol of interest.
2260  *
2261  *		If the protocol is supported, it will have an entry
2262  *		in the nvpair attribute list that can be retrieved.
2263  *
2264  *		If the entry cannot be retrieved, the protocol is not
2265  *		supported.
2266  */
2267 int
hba_supports_protocol(dm_descriptor_t hba,char * attr,boolean_t * bool)2268 hba_supports_protocol(
2269 	dm_descriptor_t	hba,
2270 	char		*attr,
2271 	boolean_t	*bool)
2272 {
2273 	nvlist_t	*attrs	= NULL;
2274 	int		error	= 0;
2275 
2276 	*bool = B_FALSE;
2277 
2278 	if ((error = get_cached_attributes(hba, &attrs)) != 0) {
2279 	    return (error);
2280 	}
2281 
2282 	*bool = (0 == nvlist_lookup_boolean(attrs, attr));
2283 
2284 	return (error);
2285 }
2286 
2287 /*
2288  * FUNCTION:	slice_set_size(dm_descriptor_t slice, uint64_t size)
2289  *
2290  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2291  *
2292  * OUTPUT:	size	- a uint64_t value representing the size of the
2293  *			slice.
2294  *
2295  * RETURNS:	int	- 0 on success
2296  *			 !0 otherwise.
2297  *
2298  * PURPOSE:	Wrapper around slice_set_uint64_attribute which converts
2299  *		the input size in bytes to blocks prior to storing it.
2300  *
2301  *		This function is used when an existing slice gets resized
2302  *		to provide space for a new slice. It is necessary to update
2303  *		the slice's size so that it is accurate.
2304  */
2305 int
slice_set_size(dm_descriptor_t slice,uint64_t size)2306 slice_set_size(
2307 	dm_descriptor_t	slice,
2308 	uint64_t	size)
2309 {
2310 	dm_descriptor_t	disk	= NULL;
2311 	uint64_t	blksize	= 0;
2312 	int		error	= 0;
2313 
2314 	((error = slice_get_disk(slice, &disk)) != 0) ||
2315 	(error = disk_get_blocksize(disk, &blksize)) ||
2316 	(error = slice_set_size_in_blocks(slice, (uint64_t)(size / blksize)));
2317 
2318 	return (error);
2319 }
2320 
2321 /*
2322  * FUNCTION:	slice_set_size_in_blocks(dm_descriptor_t slice, uint64_t size)
2323  *
2324  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2325  *
2326  * OUTPUT:	size	- a uint64_t value representing the size of the
2327  *			slice.
2328  *
2329  * RETURNS:	int	- 0 on success
2330  *			 !0 otherwise.
2331  *
2332  * PURPOSE:	Wrapper around slice_set_uint64_attribute to set the slice
2333  *		size.
2334  *
2335  *		This function is used when an existing slice gets resized
2336  *		to provide space for a new slice. It is necessary to update
2337  *		the slice's size so that it is accurate.
2338  */
2339 int
slice_set_size_in_blocks(dm_descriptor_t slice,uint64_t size)2340 slice_set_size_in_blocks(
2341 	dm_descriptor_t	slice,
2342 	uint64_t	size)
2343 {
2344 	return (slice_set_attribute(slice, DM_SIZE, size));
2345 }
2346 
2347 /*
2348  * FUNCTION:	slice_set_start_block(dm_descriptor_t slice, uint64_t start)
2349  *
2350  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2351  *
2352  * OUTPUT:	size	- a uint64_t value representing the start block of the
2353  *			slice.
2354  *
2355  * RETURNS:	int	- 0 on success
2356  *			 !0 otherwise.
2357  *
2358  * PURPOSE:	Wrapper around slice_set_attribute.
2359  *
2360  *		This function is used when an existing slice gets adjusted
2361  *		due to being resized or combined with another slice.
2362  */
2363 int
slice_set_start_block(dm_descriptor_t slice,uint64_t start)2364 slice_set_start_block(
2365 	dm_descriptor_t	slice,
2366 	uint64_t	start)
2367 {
2368 	return (slice_set_attribute(slice, DM_START, start));
2369 }
2370 
2371 /*
2372  * FUNCTION:	slice_get_start_block(dm_descriptor_t slice, uint64_t *val)
2373  *		slice_get_size_in_blocks(dm_descriptor_t slice, uint64_t *val)
2374  *		slice_get_start(dm_descriptor_t slice, uint64_t *val)
2375  *		slice_get_size(dm_descriptor_t slice, uint64_t *val)
2376  *		slice_get_index(dm_descriptor_t slice, uint64_t *val)
2377  *
2378  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2379  *
2380  * OUTPUT:	*val	- a pointer to a uint64_t to hold the
2381  *			current value of the desired attribute.
2382  *
2383  * RETURNS:	int	- 0 on success
2384  *			 !0 otherwise.
2385  *
2386  * PURPOSE:	Wrappers around slice_get_uint64_attribute which retrieve
2387  *		specific attribute values.
2388  */
2389 int
slice_get_start_block(dm_descriptor_t slice,uint64_t * val)2390 slice_get_start_block(
2391 	dm_descriptor_t	slice,
2392 	uint64_t	*val)
2393 {
2394 	return (slice_get_uint64_attribute(slice, DM_START, val));
2395 }
2396 
2397 int
slice_get_size_in_blocks(dm_descriptor_t slice,uint64_t * val)2398 slice_get_size_in_blocks(
2399 	dm_descriptor_t	slice,
2400 	uint64_t	*val)
2401 {
2402 	return (slice_get_uint64_attribute(slice, DM_SIZE, val));
2403 }
2404 
2405 int
slice_get_start(dm_descriptor_t slice,uint64_t * val)2406 slice_get_start(
2407 	dm_descriptor_t	slice,
2408 	uint64_t	*val)
2409 {
2410 	dm_descriptor_t	disk	= NULL;
2411 	uint64_t	blksize	= 0;
2412 	uint64_t	nblks	= 0;
2413 	int		error	= 0;
2414 
2415 	((error = slice_get_disk(slice, &disk)) != 0) ||
2416 	(error = disk_get_blocksize(disk, &blksize)) ||
2417 	(error = slice_get_start_block(slice, &nblks));
2418 
2419 	if (error == 0) {
2420 	    *val = (blksize * nblks);
2421 	}
2422 
2423 	return (error);
2424 }
2425 
2426 int
slice_get_size(dm_descriptor_t slice,uint64_t * val)2427 slice_get_size(
2428 	dm_descriptor_t	slice,
2429 	uint64_t	*val)
2430 {
2431 	dm_descriptor_t	disk	= NULL;
2432 	uint64_t	blksize	= 0;
2433 	uint64_t	nblks	= 0;
2434 	int		error	= 0;
2435 
2436 	*val = 0;
2437 
2438 	((error = slice_get_disk(slice, &disk)) != 0) ||
2439 	(error = slice_get_size_in_blocks(slice, &nblks)) ||
2440 	(error = disk_get_blocksize(disk, &blksize));
2441 
2442 	if (error == 0) {
2443 	    *val = (blksize * nblks);
2444 	}
2445 
2446 	return (error);
2447 }
2448 
2449 int
slice_get_index(dm_descriptor_t slice,uint32_t * val)2450 slice_get_index(
2451 	dm_descriptor_t	slice,
2452 	uint32_t	*val)
2453 {
2454 	uint64_t	index = 0;
2455 	int		error = 0;
2456 
2457 	if ((error = slice_get_uint64_attribute(
2458 	    slice, DM_INDEX, &index)) != 0) {
2459 	    return (error);
2460 	}
2461 
2462 	*val = (uint32_t)index;
2463 
2464 	return (0);
2465 }
2466 
2467 /*
2468  * FUNCTION:	slice_set_uint64_attribute(dm_descriptor_t slice,
2469  *			char *attr, uint64_t val)
2470  * 		slice_get_uint64_attribute(dm_descriptor_t slice,
2471  *			char *attr, uint64_t *val)
2472  *
2473  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2474  *		attr    - a char * attribute name
2475  *		val	- auint64_t value
2476  *
2477  * OUTPUT:	*val	- a pointer to a uint64_t to hold the
2478  *			current value of the named attribute.
2479  *
2480  * RETURNS:	int	- 0 on success
2481  *			 !0 otherwise.
2482  *
2483  * PURPOSE:	Helpers to set/get the value for a slice's attribute.
2484  *
2485  *		Consolidate the details of getting/setting slice
2486  *		attributes.  Some attributes are actually stored as
2487  *		uint32_t or uint16_t values, these functions mask
2488  *		the type conversions.
2489  */
2490 static int
slice_get_uint64_attribute(dm_descriptor_t slice,char * attr,uint64_t * val)2491 slice_get_uint64_attribute(
2492 	dm_descriptor_t	slice,
2493 	char		*attr,
2494 	uint64_t	*val)
2495 {
2496 	nvlist_t	*attrs	= NULL;
2497 	uint32_t	ui32	= 0;
2498 	int		error	= 0;
2499 
2500 	if ((error = get_cached_attributes(slice, &attrs)) != 0) {
2501 	    return (error);
2502 	}
2503 
2504 	if (strcmp(attr, DM_INDEX) == 0) {
2505 	    error = get_uint32(attrs, attr, &ui32);
2506 	    *val = (uint64_t)ui32;
2507 	} else if (strcmp(attr, DM_START) == 0) {
2508 	    error = get_uint64(attrs, attr, val);
2509 	} else if (strcmp(attr, DM_SIZE) == 0) {
2510 	    error = get_uint64(attrs, attr, val);
2511 	} else if (strcmp(attr, ATTR_DISK_FOR_SLICE) == 0) {
2512 	    error = get_uint64(attrs, attr, val);
2513 	}
2514 
2515 	if (error != 0) {
2516 	    print_get_desc_attr_error(slice, "slice", attr, error);
2517 	}
2518 
2519 	return (error);
2520 }
2521 
2522 /*
2523  * Set a slice attribute.  The attribute is only set in the cached
2524  * copy of the slice's nvpair attribute list.  This function does
2525  * NOT affect the underlying physical device.
2526  */
2527 static int
slice_set_attribute(dm_descriptor_t slice,char * attr,uint64_t val)2528 slice_set_attribute(
2529 	dm_descriptor_t	slice,
2530 	char		*attr,
2531 	uint64_t	val)
2532 {
2533 	nvlist_t	*attrs = NULL;
2534 	int		error = 0;
2535 
2536 	if ((error = get_cached_attributes(slice, &attrs)) != 0) {
2537 	    return (error);
2538 	}
2539 
2540 	if (strcmp(attr, DM_INDEX) == 0) {
2541 	    error = set_uint32(attrs, attr, (uint32_t)val);
2542 	} else if (strcmp(attr, DM_START) == 0) {
2543 	    error = set_uint64(attrs, attr, val);
2544 	} else if (strcmp(attr, DM_SIZE) == 0) {
2545 	    error = set_uint64(attrs, attr, val);
2546 	} else if (strcmp(attr, ATTR_DISK_FOR_SLICE) == 0) {
2547 	    error = set_uint64(attrs, attr, val);
2548 	}
2549 
2550 	if (error != 0) {
2551 	    print_set_desc_attr_error(slice, "slice", attr, error);
2552 	}
2553 
2554 	return (error);
2555 }
2556 
2557 /*
2558  * FUNCTION:	virtual_slice_get_disk(dm_descriptor_t slice,
2559  *			dm_descriptor_t *diskp)
2560  *
2561  * INPUT:	slice	- a dm_descriptor_t virtual slice handle
2562  *		diskp	- pointer to a dm_descriptor_t disk handle
2563  *				to return the slice's disk
2564  *
2565  * OUTPUT:	the disk associated with the virtual slice.
2566  *
2567  * RETURNS:	int	- 0 on success
2568  *			 !0 otherwise
2569  *
2570  * PURPOSE:	Helper which determines the disk that the input virtual
2571  *		slice "belongs" to.
2572  *
2573  *		The virtual slice's disk is stored in the slice's nvpair
2574  *		attribute list when the slice gets created.
2575  */
2576 static int
virtual_slice_get_disk(dm_descriptor_t slice,dm_descriptor_t * diskp)2577 virtual_slice_get_disk(
2578 	dm_descriptor_t	slice,
2579 	dm_descriptor_t	*diskp)
2580 {
2581 	uint64_t disk = 0;
2582 	int	error = 0;
2583 
2584 	if ((error = slice_get_uint64_attribute(
2585 	    slice, ATTR_DISK_FOR_SLICE, &disk)) != 0) {
2586 	    return (error);
2587 	}
2588 
2589 	*diskp = (dm_descriptor_t)disk;
2590 
2591 	if (disk == 0) {
2592 	    print_get_desc_attr_error(slice, "virtual slice", "disk", error);
2593 	    return (-1);
2594 	}
2595 
2596 	return (0);
2597 }
2598 
2599 /*
2600  * FUNCTION:	slice_get_disk(dm_descriptor_t disk, dm_descriptor_t *diskp)
2601  *
2602  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2603  *
2604  * OUTPUT:	diskp	- a pointer to a dm_descriptor_t to hold the
2605  *			disk associated with the input slice
2606  *
2607  * RETURNS:	int	- 0 on success
2608  *			 !0 otherwise.
2609  *
2610  * PURPOSE:	Helper which retrieves the disk for a slice device.
2611  *
2612  *		A slice is actually connected to its disk thru an intermediate
2613  *		device known as the "media". The media concept exists to
2614  *		model drives with removeable disk media. For the purposes
2615  *		of layout, such devices aren't relevant and the intermediate
2616  *		media can mostly be ignored.
2617  */
2618 int
slice_get_disk(dm_descriptor_t slice,dm_descriptor_t * diskp)2619 slice_get_disk(
2620 	dm_descriptor_t	slice,
2621 	dm_descriptor_t *diskp)
2622 {
2623 	dm_descriptor_t	*media = NULL;
2624 
2625 	int	i = 0;
2626 	int	error = 0;
2627 
2628 	*diskp = 0;
2629 
2630 	if (is_virtual_slice(slice)) {
2631 	    return (virtual_slice_get_disk(slice, diskp));
2632 	}
2633 
2634 	media = dm_get_associated_descriptors(slice, DM_MEDIA, &error);
2635 	(void) add_descriptors_to_free(media);
2636 
2637 	if (error != 0) {
2638 	    print_get_assoc_desc_error(slice, gettext("media"), error);
2639 	} else if ((media == NULL) || (*media == NULL)) {
2640 	    print_get_assoc_desc_error(slice, gettext("media"), error);
2641 	    error = -1;
2642 	}
2643 
2644 	if (error != 0) {
2645 	    return (error);
2646 	}
2647 
2648 	/* slice should have exactly 1 media */
2649 	for (i = 0; (media[i] != NULL) && (*diskp == NULL); i++) {
2650 	    /* get disk from media */
2651 	    dm_descriptor_t *disks = NULL;
2652 	    disks = dm_get_associated_descriptors(media[i], DM_DRIVE, &error);
2653 	    (void) add_descriptors_to_free(disks);
2654 
2655 	    if ((error == 0) && (disks != NULL) && (disks[0] != NULL)) {
2656 		*diskp = disks[0];
2657 	    }
2658 	    free(disks);
2659 	}
2660 
2661 	if (media != NULL) {
2662 	    free(media);
2663 	}
2664 
2665 	if (*diskp == 0) {
2666 	    print_get_desc_attr_error(slice,
2667 		    gettext("slice"), gettext("disk"), ENODEV);
2668 	    error = -1;
2669 	}
2670 
2671 	return (error);
2672 }
2673 
2674 /*
2675  * FUNCTION:	slice_get_hbas(dm_descriptor_t slice, dlist_t **list)
2676  *
2677  * INPUT:	slice	- a dm_descriptor_t handle for a slice
2678  *
2679  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
2680  *			HBAs associated with the input slice
2681  *
2682  * RETURNS:	int	- 0 on success
2683  *			 !0 otherwise.
2684  *
2685  * PURPOSE:	Helper which retrieves the known HBAs for a slice device.
2686  *
2687  */
2688 int
slice_get_hbas(dm_descriptor_t slice,dlist_t ** list)2689 slice_get_hbas(
2690 	dm_descriptor_t	slice,
2691 	dlist_t		**list)
2692 {
2693 	dm_descriptor_t	disk	= NULL;
2694 	int		error	= 0;
2695 
2696 	*list = NULL;
2697 
2698 	((error = slice_get_disk(slice, &disk)) != 0) ||
2699 	(error = disk_get_hbas(disk, list));
2700 
2701 	if (*list == NULL) {
2702 	    print_get_desc_attr_error(slice, "slice", "HBA", ENODEV);
2703 	    error = -1;
2704 	}
2705 
2706 	return (error);
2707 }
2708 
2709 /*
2710  * FUNCTION:	disk_get_associated_desc(dm_descriptor_t disk,
2711  *			dm_desc_type_t assoc_type, char *assoc_type_str,
2712  *			dlist_t **list)
2713  *
2714  * INPUT:	disk	- a dm_descriptor_t handle for a disk
2715  *		assoc_type - the type of associated object to get
2716  *		assoc_type_str - a char * string for the associated type
2717  *
2718  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
2719  *			objects associated with the input disk
2720  *
2721  * RETURNS:	int	- 0 on success
2722  *			 !0 otherwise.
2723  *
2724  * PURPOSE:	Helper which retrieves the associated objects of the
2725  *		requested type for a disk device.
2726  */
2727 static int
disk_get_associated_desc(dm_descriptor_t disk,dm_desc_type_t assoc_type,char * assoc_type_str,dlist_t ** list)2728 disk_get_associated_desc(
2729 	dm_descriptor_t	disk,
2730 	dm_desc_type_t 	assoc_type,
2731 	char		*assoc_type_str,
2732 	dlist_t		**list)
2733 {
2734 	int	i = 0;
2735 	int	error = 0;
2736 
2737 	dm_descriptor_t	*assoc =
2738 	    dm_get_associated_descriptors(disk, assoc_type, &error);
2739 
2740 	(void) add_descriptors_to_free(assoc);
2741 
2742 	if (error == 0) {
2743 	    for (i = 0;
2744 		(assoc != NULL) && (assoc[i] != NULL) && (error == 0);
2745 		i++) {
2746 		dlist_t *item = dlist_new_item((void *)(uintptr_t)assoc[i]);
2747 		if (item == NULL) {
2748 		    error = ENOMEM;
2749 		} else {
2750 		    *list = dlist_append(item, *list, AT_TAIL);
2751 		}
2752 	    }
2753 	} else {
2754 	    print_get_assoc_desc_error(disk, assoc_type_str, error);
2755 	}
2756 
2757 	if (assoc != NULL) {
2758 	    free(assoc);
2759 	}
2760 
2761 	if (error != 0) {
2762 	    dlist_free_items(*list, NULL);
2763 	    *list = NULL;
2764 	}
2765 
2766 	return (error);
2767 }
2768 
2769 /*
2770  * FUNCTION:	disk_get_hbas(dm_descriptor_t disk, dlist_t **list)
2771  *
2772  * INPUT:	disk	- a dm_descriptor_t handle for a disk
2773  *
2774  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
2775  *			HBAs associated with the input disk
2776  *
2777  * RETURNS:	int	- 0 on success
2778  *			 !0 otherwise.
2779  *
2780  * PURPOSE:	Helper which retrieves the known HBAs for a disk device.
2781  *
2782  */
2783 int
disk_get_hbas(dm_descriptor_t disk,dlist_t ** list)2784 disk_get_hbas(
2785 	dm_descriptor_t	disk,
2786 	dlist_t		**list)
2787 {
2788 	return (disk_get_associated_desc(disk, DM_CONTROLLER,
2789 			gettext("controller"), list));
2790 }
2791 
2792 /*
2793  * FUNCTION:	disk_get_paths(dm_descriptor_t disk, dlist_t **list)
2794  *
2795  * INPUT:	disk	- a dm_descriptor_t handle for a disk
2796  *
2797  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
2798  *			paths associated with the input disk
2799  *
2800  * RETURNS:	int	- 0 on success
2801  *			 !0 otherwise.
2802  *
2803  * PURPOSE:	Helper which retrieves the known paths for a disk device.
2804  *
2805  *		Paths are managed by the MPXIO driver, they represent hardware
2806  *		paths to the disk drive managed by the MPXIO and not visible
2807  *		externally, unlike aliases which are.
2808  */
2809 int
disk_get_paths(dm_descriptor_t disk,dlist_t ** list)2810 disk_get_paths(
2811 	dm_descriptor_t	disk,
2812 	dlist_t		**list)
2813 {
2814 	return (disk_get_associated_desc(disk, DM_PATH,
2815 			gettext("path"), list));
2816 }
2817 
2818 /*
2819  * FUNCTION:	disk_get_aliases(dm_descriptor_t disk, dlist_t **list)
2820  *
2821  * INPUT:	disk	- a dm_descriptor_t handle for a disk
2822  *
2823  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
2824  *			alias descriptors associated with the input disk
2825  *
2826  * RETURNS:	int	- 0 on success
2827  *			 !0 otherwise.
2828  *
2829  * PURPOSE:	Helper which retrieves the known aliases for a disk device.
2830  *
2831  *		Aliases are the different CTD names for the disk drive when
2832  *		MPXIO is not enabled for multipathed drives.
2833  */
2834 int
disk_get_aliases(dm_descriptor_t disk,dlist_t ** list)2835 disk_get_aliases(
2836 	dm_descriptor_t	disk,
2837 	dlist_t		**list)
2838 {
2839 	return (disk_get_associated_desc(disk, DM_ALIAS,
2840 			gettext("alias"), list));
2841 }
2842 
2843 /*
2844  * FUNCTION:	compare_string_to_desc_name_or_alias(
2845  *			void *str, void *desc)
2846  *
2847  * INPUT:	str	- opaque pointer
2848  * 		descr	- opaque pointer
2849  *
2850  * RETURNS:	int	- <0 - if str < desc.name
2851  *			   0 - if str == desc.name
2852  *			  >0 - if str > desc.name
2853  *
2854  * PURPOSE:	dlist_t helper which compares a string to the name
2855  *		and aliases associated with the input dm_descriptor_t
2856  *		handle.
2857  *
2858  *		Comparison is done via compare_device_names.
2859  */
2860 static int
compare_string_to_desc_name_or_alias(void * str,void * desc)2861 compare_string_to_desc_name_or_alias(
2862 	void	*str,
2863 	void	*desc)
2864 {
2865 	char	*dname = NULL;
2866 	int	result = -1;
2867 
2868 	assert(str != (char *)NULL);
2869 	assert(desc != (dm_descriptor_t)0);
2870 
2871 	(void) get_display_name((uintptr_t)desc, &dname);
2872 
2873 	/* try name first, then aliases */
2874 	if ((result = compare_device_names(str, dname)) != 0) {
2875 	    dlist_t *aliases = NULL;
2876 
2877 	    (void) get_aliases((uintptr_t)desc, &aliases);
2878 	    if ((aliases != NULL) && (dlist_contains(aliases,
2879 			str, compare_device_names) == B_TRUE)) {
2880 		result = 0;
2881 	    }
2882 	    dlist_free_items(aliases, free);
2883 	}
2884 
2885 	return (result);
2886 }
2887 
2888 /*
2889  * FUNCTION:	hba_get_by_name(char *name, dm_descriptor_t *hba)
2890  *
2891  * INPUT:	name	- a char * disk name
2892  *
2893  * OUTPUT:	hba	- a pointer to a dm_descriptor_t to hold the
2894  *			HBA corresponding to the input name, if found
2895  *
2896  * RETURNS:	int	- 0 on success
2897  *			 !0 otherwise
2898  *
2899  * PURPOSE:	Helper which iterates the known HBAs, searching for
2900  *		the one matching name.
2901  *
2902  *		If no HBA matches the name, 0 is returned and the
2903  *		value of 'hba' will be (dm_descriptor_t)0;
2904  */
2905 int
hba_get_by_name(char * name,dm_descriptor_t * hba)2906 hba_get_by_name(
2907 	char		*name,
2908 	dm_descriptor_t *hba)
2909 {
2910 	int		error = 0;
2911 	dlist_t		*list = NULL;
2912 	dlist_t		*item = NULL;
2913 
2914 	*hba = (dm_descriptor_t)0;
2915 
2916 	if (name == NULL) {
2917 	    return (0);
2918 	}
2919 
2920 	if ((error = get_known_hbas(&list)) != 0) {
2921 	    return (error);
2922 	}
2923 
2924 	if ((item = dlist_find(list, name,
2925 	    compare_string_to_desc_name_or_alias)) != NULL) {
2926 	    *hba = (uintptr_t)item->obj;
2927 	}
2928 
2929 	return (error);
2930 }
2931 
2932 /*
2933  * FUNCTION:	disk_get_by_name(char *name, dm_descriptor_t *disk)
2934  *
2935  * INPUT:	name	- a char * disk name
2936  *
2937  * OUTPUT:	disk	- a pointer to a dm_descriptor_t to hold the
2938  *			disk corresponding to the input name, if found
2939  *
2940  * RETURNS:	int	- 0 on success
2941  *			 !0 otherwise.
2942  *
2943  * PURPOSE:	Helper which retrieves a dm_descriptor_t disk handle
2944  *		by name.
2945  *
2946  *		If no disk is found for the input name, variations of
2947  *		the name are tried.
2948  *
2949  *		If the input name is unqualified, an appropriate leading
2950  *		path is prepended.
2951  *
2952  *		If the input name is qualified, the leading path is
2953  *		removed.
2954  *
2955  *		If no disk is found for the variations, 0 is returned
2956  *		and the	value of 'disk' will be (dm_descriptor_t)0;
2957  */
2958 int
disk_get_by_name(char * name,dm_descriptor_t * disk)2959 disk_get_by_name(
2960 	char		*name,
2961 	dm_descriptor_t *disk)
2962 {
2963 	assert(name != (char *)NULL);
2964 
2965 	*disk = find_cached_descriptor(name);
2966 	if (*disk == (dm_descriptor_t)0) {
2967 	    if (name[0] == '/') {
2968 		/* fully qualified, try unqualified */
2969 		char *cp = strrchr(name, '/');
2970 		if (cp != NULL) {
2971 		    *disk = find_cached_descriptor(cp + 1);
2972 		}
2973 	    } else {
2974 		/* unqualified, try fully qualified */
2975 		char buf[MAXNAMELEN+1];
2976 		if (is_ctd_disk_name(name)) {
2977 		    (void) snprintf(buf, MAXNAMELEN, "/dev/dsk/%s", name);
2978 		} else if (is_did_disk_name(name)) {
2979 		    (void) snprintf(buf, MAXNAMELEN, "/dev/did/dsk/%s", name);
2980 		}
2981 		*disk = find_cached_descriptor(buf);
2982 	    }
2983 	}
2984 
2985 	/*
2986 	 * since the descriptor cache includes HBAs, disks and slices,
2987 	 * what gets returned may not be a disk... make sure it is
2988 	 */
2989 	if (*disk != (dm_descriptor_t)0) {
2990 	    if (dm_get_type(*disk) != DM_DRIVE) {
2991 		*disk = (dm_descriptor_t)0;
2992 	    }
2993 	}
2994 
2995 	return (0);
2996 }
2997 
2998 /*
2999  * FUNCTION:	slice_get_by_name(char *name, dm_descriptor_t *slice)
3000  *
3001  * INPUT:	name	- a char * slice name
3002  *
3003  * OUTPUT:	slice	- a pointer to a dm_descriptor_t to hold the
3004  *			slice corresponding to the input name, if found.
3005  *
3006  * RETURNS:	int	- 0 on success
3007  *			 !0 otherwise.
3008  *
3009  * PURPOSE:	Helper which iterates the known slices, searching for
3010  *		the one matching name.
3011  *
3012  *		If no slice is found for the input name, variations of
3013  *		the name are tried.
3014  *
3015  *		If the input name is unqualified, an appropriate leading
3016  *		path is prepended.
3017  *
3018  *		If the input name is qualified, the leading path is
3019  *		removed.
3020  *
3021  *		If no slice matches the variations, 0 is returned and the
3022  *		value of 'slice' will be (dm_descriptor_t)0;
3023  */
3024 int
slice_get_by_name(char * name,dm_descriptor_t * slice)3025 slice_get_by_name(
3026 	char		*name,
3027 	dm_descriptor_t *slice)
3028 {
3029 	assert(name != (char *)NULL);
3030 
3031 	*slice = find_cached_descriptor(name);
3032 	if (*slice == (dm_descriptor_t)0) {
3033 	    if (name[0] == '/') {
3034 		/* fully qualified, try unqualified */
3035 		char *cp = strrchr(name, '/');
3036 		if (cp != NULL) {
3037 		    *slice = find_cached_descriptor(cp + 1);
3038 		}
3039 	    } else {
3040 		/* unqualified, try fully qualified */
3041 		char buf[MAXNAMELEN+1];
3042 		if (is_ctd_slice_name(name) || is_ctd_like_slice_name(name) ||
3043 			is_bsd_like_slice_name(name)) {
3044 		    (void) snprintf(buf, MAXNAMELEN, "/dev/dsk/%s", name);
3045 		} else if (is_did_slice_name(name)) {
3046 		    (void) snprintf(buf, MAXNAMELEN, "/dev/did/dsk/%s", name);
3047 		}
3048 		*slice = find_cached_descriptor(buf);
3049 	    }
3050 	}
3051 
3052 	/*
3053 	 * since the descriptor cache includes HBAs, disks and slices,
3054 	 * what gets returned may not be a slice... make sure it is
3055 	 */
3056 	if (*slice != (dm_descriptor_t)0) {
3057 	    if (dm_get_type(*slice) != DM_SLICE &&
3058 		is_virtual_slice(*slice) != B_TRUE) {
3059 		*slice = (dm_descriptor_t)0;
3060 	    }
3061 	}
3062 
3063 	return (0);
3064 }
3065 
3066 /*
3067  * FUNCTION:	extract_hbaname(char *name, char **hbaname)
3068  *
3069  * INPUT:	slicename - a char * device name
3070  *
3071  * OUTPUT:	hbaname - a pointer to a char * to hold the hbaname derived
3072  *			from the input name.
3073  *
3074  * RETURNS:	int	- 0 on success
3075  *			 !0 otherwise.
3076  *
3077  * PURPOSE:	Helper which extracts the HBA name from the input name.
3078  *
3079  *		If the input name is in ctd form, extracts just the cX part,
3080  *		by truncating everything following the last 't'.
3081  *
3082  *		Of course on X86, with IDE drives, there is no 't' in the
3083  *		ctd name, so start by truncating everything following 'd'
3084  *		and then look for 't'.
3085  *
3086  * 		The returned string must be passed to free().
3087  */
3088 int
extract_hbaname(char * name,char ** hbaname)3089 extract_hbaname(
3090 	char	*name,
3091 	char	**hbaname)
3092 {
3093 	char	*cp;
3094 
3095 	if (is_ctd_name(name)) {
3096 	    if ((*hbaname = strdup(name)) == NULL) {
3097 		return (ENOMEM);
3098 	    }
3099 	    if ((cp = strrchr(*hbaname, 'd')) != NULL) {
3100 		*cp = '\0';
3101 	    }
3102 	    if ((cp = strrchr(*hbaname, 't')) != NULL) {
3103 		*cp = '\0';
3104 	    }
3105 	}
3106 
3107 	return (0);
3108 }
3109 
3110 /*
3111  * FUNCTION:	extract_diskname(char *slicename, char **diskname)
3112  *
3113  * INPUT:	slicename - a char * slice name
3114  *
3115  * OUTPUT:	diskname - a pointer to a char * to hold the diskname derived
3116  *			from the input slicename.
3117  *
3118  * RETURNS:	int	- 0 on success
3119  *			 !0 otherwise.
3120  *
3121  * PURPOSE:	Helper which extracts the disk's name from a slice name.
3122  *
3123  *		Checks to see if the input slicename is in ctd or did form,
3124  *		and if so, truncates everything following the last 's'.
3125  *
3126  *		If the input slicename is BSD-like, truncate the last
3127  *		character (a-h).
3128  *
3129  * 		The returned string must be passed to free().
3130  */
3131 int
extract_diskname(char * slicename,char ** diskname)3132 extract_diskname(
3133 	char	*slicename,
3134 	char	**diskname)
3135 {
3136 	char	*cp;
3137 
3138 	if (is_ctd_slice_name(slicename) || is_did_slice_name(slicename) ||
3139 	    is_ctd_like_slice_name(slicename)) {
3140 
3141 	    if ((*diskname = strdup(slicename)) == NULL) {
3142 		return (ENOMEM);
3143 	    }
3144 	    if ((cp = strrchr(*diskname, 's')) != NULL) {
3145 		*cp = '\0';
3146 	    }
3147 
3148 	} else if (is_bsd_like_slice_name(slicename)) {
3149 
3150 	    if ((*diskname = strdup(slicename)) == NULL) {
3151 		return (ENOMEM);
3152 	    }
3153 	    (*diskname)[strlen((*diskname)-1)] = '\0';
3154 
3155 	}
3156 
3157 	return (0);
3158 }
3159 
3160 /*
3161  * FUNCTION:	get_disk_for_named_slice(char *slicename,
3162  *			dm_descriptor_t disk)
3163  *
3164  * INPUT:	slicename - a char * slice name
3165  *
3166  * OUTPUT:	disk	- a pointer to a dm_descriptor_t to hold the
3167  *			disk corresponding to the input name, if found
3168  *
3169  * RETURNS:	int	- 0 on success
3170  *			 !0 otherwise.
3171  *
3172  * PURPOSE:	Helper which locates the disk dm_descriptor_t handle for
3173  *		the input slice name.
3174  *
3175  *		If no disk matches the name, 0 is returned and the
3176  *		value of 'disk' will be (dm_descriptor_t)0;
3177  */
3178 int
get_disk_for_named_slice(char * slicename,dm_descriptor_t * disk)3179 get_disk_for_named_slice(
3180 	char		*slicename,
3181 	dm_descriptor_t *disk)
3182 {
3183 	dm_descriptor_t slice = (dm_descriptor_t)0;
3184 	int		error = 0;
3185 
3186 	assert(slicename != NULL);
3187 
3188 	/* find disk for slice */
3189 	if ((error = slice_get_by_name(slicename, &slice)) == 0) {
3190 
3191 	    if (slice != (dm_descriptor_t)0) {
3192 		error = slice_get_disk(slice, disk);
3193 	    } else {
3194 		/* named slice was created by layout: */
3195 		/* need to find disk by name */
3196 		char *dname;
3197 
3198 		error = extract_diskname(slicename, &dname);
3199 		if (error == 0) {
3200 		    error = disk_get_by_name(dname, disk);
3201 		}
3202 		free(dname);
3203 	    }
3204 	}
3205 
3206 	assert(*disk != (dm_descriptor_t)0);
3207 
3208 	return (error);
3209 }
3210 
3211 /*
3212  * FUNCTION:	disk_get_reserved_indexes(dm_descriptor_t disk,
3213  *			uint16_t **array)
3214  *
3215  * INPUT:	disk	- a dm_descriptor_t disk handle
3216  *
3217  * RETURNS:	int	- 0 on success
3218  *			 !0 otherwise
3219  *
3220  * PURPOSE:	Retrieves the input disk's list of reserved slice indices.
3221  *
3222  *		The list of reserved indices is stored as an array in
3223  *		the disk's nvpair attribute list.
3224  */
3225 static int
disk_get_reserved_indexes(dm_descriptor_t disk,uint16_t ** array)3226 disk_get_reserved_indexes(
3227 	dm_descriptor_t	disk,
3228 	uint16_t	**array)
3229 {
3230 	nvlist_t	*attrs = NULL;
3231 	uint_t		nelem = 0;
3232 	int		error = 0;
3233 
3234 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
3235 	    return (error);
3236 	}
3237 
3238 	if ((error = get_uint16_array(
3239 	    attrs, ATTR_RESERVED_INDEX, array, &nelem)) != 0) {
3240 	    if (error == ENOENT) {
3241 		/* no reserved indices yet */
3242 		error = 0;
3243 	    }
3244 	}
3245 
3246 	return (error);
3247 }
3248 
3249 /*
3250  * FUNCTION:	disk_reserve_index(dm_descriptor_t disk, uint16_t index)
3251  *
3252  * INPUT:	disk	- a disk dm_descirptor_t handle
3253  *		undex	- a VTOC slice index
3254  *
3255  * RETURNS:	int	- 0 on success
3256  *			 !0 otherwise
3257  *
3258  * PURPOSE:	Reserves the input VTOC slice index for the input disk.
3259  *
3260  *		The list of reserved indices is stored as an array in
3261  *		the disk's nvpair attribute list.
3262  */
3263 int
disk_reserve_index(dm_descriptor_t disk,uint16_t index)3264 disk_reserve_index(
3265 	dm_descriptor_t	disk,
3266 	uint16_t	index)
3267 {
3268 	nvlist_t	*attrs = NULL;
3269 	uint16_t	*oldindexes = NULL;
3270 	uint16_t	*newindexes = NULL;
3271 	uint_t		nelem = 0;
3272 	int		error = 0;
3273 	int		i = 0;
3274 
3275 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
3276 	    return (error);
3277 	}
3278 
3279 	if ((error = get_uint16_array(
3280 	    attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) {
3281 	    if (error != ENOENT) {
3282 		return (error);
3283 	    }
3284 	    /* no reserved indices yet */
3285 	    error = 0;
3286 	}
3287 
3288 	/* add new index */
3289 	newindexes = (uint16_t *)calloc(VTOC_SIZE, sizeof (uint16_t));
3290 	if (newindexes != NULL) {
3291 	    for (i = 0; i < nelem; i++) {
3292 		newindexes[i] = oldindexes[i];
3293 	    }
3294 	    newindexes[(int)index] = 1;
3295 
3296 	    error = set_uint16_array(attrs, ATTR_RESERVED_INDEX,
3297 		    newindexes, VTOC_SIZE);
3298 
3299 	    free(newindexes);
3300 	} else {
3301 	    error = ENOMEM;
3302 	}
3303 	return (error);
3304 }
3305 
3306 /*
3307  * FUNCTION:	disk_release_index(dm_descriptor_t disk, uint16_t index)
3308  *
3309  * INPUT:	disk	- a disk dm_descirptor_t handle
3310  *		undex	- a VTOC slice index
3311  *
3312  * RETURNS:	int	- 0 on success
3313  *			 !0 otherwise
3314  *
3315  * PURPOSE:	Releases the input VTOC slice index for the input disk.
3316  *		The index was previously reserved by disk_reserve_index()
3317  */
3318 int
disk_release_index(dm_descriptor_t disk,uint16_t index)3319 disk_release_index(
3320 	dm_descriptor_t	disk,
3321 	uint16_t	index)
3322 {
3323 	nvlist_t	*attrs = NULL;
3324 	uint16_t	*oldindexes = NULL;
3325 	uint16_t	*newindexes = NULL;
3326 	uint_t		nelem = 0;
3327 	int		error = 0;
3328 	int		i = 0;
3329 
3330 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
3331 	    return (error);
3332 	}
3333 
3334 	if ((error = get_uint16_array(
3335 	    attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) {
3336 	    if (error != ENOENT) {
3337 		return (error);
3338 	    }
3339 	    error = 0;
3340 	}
3341 
3342 	newindexes = (uint16_t *)calloc(VTOC_SIZE, sizeof (uint16_t));
3343 	if (newindexes != NULL) {
3344 	    for (i = 0; i < nelem; i++) {
3345 		newindexes[i] = oldindexes[i];
3346 	    }
3347 
3348 	    /* release index */
3349 	    newindexes[(int)index] = 0;
3350 
3351 	    error = set_uint16_array(attrs, ATTR_RESERVED_INDEX,
3352 		    newindexes, VTOC_SIZE);
3353 
3354 	    free(newindexes);
3355 	} else {
3356 	    error = ENOMEM;
3357 	}
3358 
3359 	return (error);
3360 }
3361 
3362 /*
3363  * FUNCTION:	print_get_assoc_desc_error(dm_descriptor_t desc, char *which,
3364  *			int error)
3365  *
3366  * INPUT:	desc	- a dm_descriptor_t handle
3367  *		which	- a char * indicating which association
3368  *		error	- an integer error value
3369  *
3370  * PURPOSE:	Utility function to print an error message for a failed
3371  *		call to dm_get_associated_descriptors().
3372  *
3373  *		Extracts the device's CTD name and formats an error message.
3374  */
3375 void
print_get_assoc_desc_error(dm_descriptor_t desc,char * which,int error)3376 print_get_assoc_desc_error(
3377 	dm_descriptor_t desc,
3378 	char		*which,
3379 	int		error)
3380 {
3381 	char *name = "";
3382 
3383 	(void) get_display_name(desc, &name);
3384 	oprintf(OUTPUT_TERSE,
3385 		gettext("dm_get_associated_descriptors(%s) for "
3386 			"'%s' failed: %d\n"),
3387 		which, name, error);
3388 
3389 	volume_set_error(
3390 		gettext("Unexpected error getting associated "
3391 			"descriptors for '%s'"),
3392 			name);
3393 }
3394 
3395 /*
3396  * FUNCTION:	print_get_desc_attr_error(dm_descriptor_t desc,
3397  *			char *devtype, char *attr, int error)
3398  *
3399  * INPUT:	desc	- a dm_descriptor_t handle
3400  *		devtype	- a char * device type that's being accessed
3401  *		attr	- a char * attribute name
3402  *		error	- an integer error value
3403  *
3404  * PURPOSE:	Shared utility function to print an error message for a failed
3405  *		call to retrieve an attribute for a descriptor.
3406  *
3407  *		Extracts the device's CTD name and formats an error message.
3408  */
3409 void
print_get_desc_attr_error(dm_descriptor_t desc,char * devtype,char * attr,int error)3410 print_get_desc_attr_error(
3411 	dm_descriptor_t desc,
3412 	char		*devtype,
3413 	char		*attr,
3414 	int		error)
3415 {
3416 	char *name = "";
3417 
3418 	(void) get_display_name(desc, &name);
3419 	oprintf(OUTPUT_TERSE,
3420 		gettext("'%s' get attribute (%s.%s) error: %d\n"),
3421 		name, devtype, attr, error);
3422 
3423 	volume_set_error(
3424 		gettext("Unexpected error getting attribute '%s.%s' for '%s'"),
3425 			devtype, attr, name);
3426 }
3427 
3428 /*
3429  * FUNCTION:	print_set_desc_attr_error(dm_descriptor_t desc,
3430  *			char *devtype, char *attr, int error)
3431  *
3432  * INPUT:	desc	- a dm_descriptor_t handle
3433  *		devtype	- a char * device type that's being accessed
3434  *		attr	- a char * attribute name
3435  *		error	- an integer error value
3436  *
3437  * PURPOSE:	Shared utility function to print an error message for a failed
3438  *		call to set an attribute for a descriptor.
3439  *
3440  *		Extracts the device's CTD name and formats an error message.
3441  */
3442 void
print_set_desc_attr_error(dm_descriptor_t desc,char * devtype,char * attr,int error)3443 print_set_desc_attr_error(
3444 	dm_descriptor_t desc,
3445 	char		*devtype,
3446 	char		*attr,
3447 	int		error)
3448 {
3449 	char *name = "";
3450 
3451 	(void) get_display_name(desc, &name);
3452 	oprintf(OUTPUT_TERSE,
3453 		gettext("'%s' set attribute (%s.%s) error: %d\n"),
3454 		name, devtype, attr, error);
3455 
3456 	volume_set_error(
3457 		gettext("Unexpected error setting attribute '%s.%s' for '%s'"),
3458 			devtype, attr, name);
3459 }
3460