7712 mandoc -Tlint does always exit with error code 0
[unleashed.git] / usr / src / cmd / lvm / metassist / layout / layout_device_util.c
blob687cd44a5cb0eac9ff5559e2233464153d726e2f
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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>
38 #include <libdiskmgt.h>
39 #include "meta_repartition.h"
41 #define _LAYOUT_DEVICE_UTIL_C
43 #include "volume_dlist.h"
44 #include "volume_error.h"
45 #include "volume_output.h"
46 #include "volume_nvpair.h"
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"
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.
60 #define QUOTE(x) #x
61 #define VAL2STR(x) QUOTE(x)
63 /* private utilities for disks */
64 static int disk_get_uint64_attribute(
65 dm_descriptor_t disk,
66 char *attr,
67 uint64_t *val);
69 static int disk_get_boolean_attribute(
70 dm_descriptor_t disk,
71 char *attr,
72 boolean_t *bool);
74 static int disk_get_rpm(
75 dm_descriptor_t disk,
76 uint32_t *val);
78 static int disk_get_sync_speed(
79 dm_descriptor_t disk,
80 uint32_t *val);
82 static int disk_has_virtual_slices(
83 dm_descriptor_t disk,
84 boolean_t *bool);
86 static int disk_get_virtual_slices(
87 dm_descriptor_t disk,
88 dlist_t **list);
90 static int disk_get_reserved_indexes(
91 dm_descriptor_t disk,
92 uint16_t **array);
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);
100 /* utilities for slices */
101 static int slice_get_uint64_attribute(
102 dm_descriptor_t slice,
103 char *attr,
104 uint64_t *val);
106 static int slice_set_attribute(
107 dm_descriptor_t slice,
108 char *attr,
109 uint64_t val);
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.
118 static dlist_t *_virtual_slices = NULL;
120 /* temporary implementation */
121 static int virtual_repartition_drive(
122 dm_descriptor_t disk,
123 mdvtoc_t *vtocp);
125 static int disk_add_virtual_slice(
126 dm_descriptor_t disk,
127 dm_descriptor_t slice);
129 static int virtual_slice_get_disk(
130 dm_descriptor_t slice,
131 dm_descriptor_t *diskp);
134 * attribute names for layout private information stored in
135 * device nvpair attribute lists.
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";
144 * FUNCTION: is_ctd_like_slice_name(char *name)
145 * INPUT: name - a char *
147 * RETURNS: boolean_t - B_TRUE - if name follows an alternate slice
148 * naming scheme similar to CTD
149 * B_FALSE - otherwise
151 * PURPOSE: Determines if the input name is of the form XXXsNNN
152 * (e.g., whizzy0s1)
154 boolean_t
155 is_ctd_like_slice_name(
156 char *name)
158 uint_t s = 0;
159 uint_t d = 0;
160 int l = 0;
161 boolean_t is = B_FALSE;
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;
171 return (is);
175 * FUNCTION: is_bsd_like_slice_name(char *name)
176 * INPUT: name - a char *
178 * RETURNS: boolean_t - B_TRUE - if name follows an alternate slice
179 * BSD-like naming scheme
180 * B_FALSE - otherwise
182 * PURPOSE: Determines if the input name is of the form XXXNNN[a-h]
183 * (e.g., whizzy0a)
185 boolean_t
186 is_bsd_like_slice_name(
187 char *name)
189 uint_t d = 0;
190 int l = 0;
191 boolean_t is = B_FALSE;
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;
201 return (is);
205 * FUNCTION: is_did_name(char *name)
206 * INPUT: name - a char *
208 * RETURNS: boolean_t - B_TRUE - if name is from the DID namespace
209 * B_FALSE - otherwise
211 * PURPOSE: Determines if the input name is from the DID namespace.
213 boolean_t
214 is_did_name(
215 char *name)
217 return (is_did_slice_name(name) || is_did_disk_name(name));
221 * FUNCTION: is_did_slice_name(char *name)
222 * INPUT: name - a char *
224 * RETURNS: boolean_t - B_TRUE - if name represents a slice from the DID
225 * namespace
226 * B_FALSE - otherwise
228 * PURPOSE: Determines if the input name is a slice from the DID namespace.
230 boolean_t
231 is_did_slice_name(
232 char *name)
234 uint_t d = 0, s = 0;
235 int l = 0;
236 boolean_t is = B_FALSE;
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;
245 return (is);
249 * FUNCTION: is_did_disk_name(char *name)
250 * INPUT: name - a char *
252 * RETURNS: boolean_t - B_TRUE - if name represents a disk from the DID
253 * namespace
254 * B_FALSE - otherwise
256 * PURPOSE: Determines if the input name is a disk from the DID namespace.
258 boolean_t
259 is_did_disk_name(
260 char *name)
262 uint_t d = 0;
263 int l = 0;
264 boolean_t is = B_FALSE;
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;
273 return (is);
277 * FUNCTION: is_ctd_name(char *name)
278 * INPUT: name - a char *
280 * RETURNS: boolean_t - B_TRUE - if name is from the CTD namespace
281 * B_FALSE - otherwise
283 * PURPOSE: Determines if the input name is from the CTD namespace.
285 * {/dev/dsk/, /dev/rdsk/}cXtXdXsX
286 * {/dev/dsk/, /dev/rdsk/}cXtXdX
287 * {/dev/dsk/, /dev/rdsk/}cXdXsX
288 * {/dev/dsk/, /dev/rdsk/}cXdX
290 boolean_t
291 is_ctd_name(
292 char *name)
294 return (is_ctd_slice_name(name) || is_ctd_disk_name(name) ||
295 is_ctd_target_name(name) || is_ctd_ctrl_name(name));
299 * FUNCTION: is_ctd_slice_name(char *name)
300 * INPUT: name - a char *
302 * RETURNS: boolean_t - B_TRUE - if name represents a slice from the CTD
303 * namespace
304 * B_FALSE - otherwise
306 * PURPOSE: Determines if the input name is a slice name from the
307 * CTD namespace.
309 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>dXsX
310 * {/dev/dsk/, /dev/rdsk/}cXtXdXsX
311 * {/dev/dsk/, /dev/rdsk/}cXdXsX
313 boolean_t
314 is_ctd_slice_name(
315 char *name)
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;
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;
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))) {
345 char wwn[MAXNAMELEN+2];
347 /* buf ends with "dXsX", truncate at the 'd' */
348 *dev_pos = '\0';
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;
358 return (is);
362 * FUNCTION: is_ctd_disk_name(char *name)
363 * INPUT: name - a char *
365 * RETURNS: boolean_t - B_TRUE - if name represents a disk from the CTD
366 * namespace
367 * B_FALSE - otherwise
369 * PURPOSE: Determines if the input name is a disk name from the
370 * CTD namespace.
372 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>dX
373 * {/dev/dsk/, /dev/rdsk/}cXtXdX
374 * {/dev/dsk/, /dev/rdsk/}cXdX
376 boolean_t
377 is_ctd_disk_name(
378 char *name)
380 uint_t c = 0, t = 0, d = 0;
381 int l = 0;
382 char buf[MAXNAMELEN+1];
383 boolean_t is = B_FALSE;
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;
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))) {
406 char wwn[MAXNAMELEN+2];
408 /* buf ends with "dX", truncate at the 'd' */
409 *dev_pos = '\0';
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;
419 return (is);
423 * FUNCTION: is_ctd_disk_name(char *name)
424 * INPUT: name - a char *
426 * RETURNS: boolean_t - B_TRUE - if name represents a target from the CTD
427 * namespace
428 * B_FALSE - otherwise
430 * PURPOSE: Determines if the input name is a target name from the
431 * CTD namespace.
433 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>
434 * {/dev/dsk/, /dev/rdsk/}cXtX
436 boolean_t
437 is_ctd_target_name(
438 char *name)
440 uint_t c = 0, t = 0;
441 int l = 0;
442 char buf[MAXNAMELEN+1];
443 boolean_t is = B_FALSE;
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))) {
458 char wwn[MAXNAMELEN+2];
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;
467 return (is);
471 * FUNCTION: is_ctd_ctrl_name(char *name)
472 * INPUT: name - a char *
474 * RETURNS: boolean_t - B_TRUE - if name represents a controller/hba
475 * from the CTD namespace
476 * B_FALSE - otherwise
478 * PURPOSE: Determines if the input name is an HBA name from the
479 * CTD namespace.
481 * {/dev/dsk/, /dev/rdsk/}cX
483 boolean_t
484 is_ctd_ctrl_name(
485 char *name)
487 uint_t c = 0;
488 int l = 0;
489 boolean_t is = B_FALSE;
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;
498 return (is);
502 * FUNCTION: set_display_name(dm_descriptor_t desc, char *name)
503 * get_display_name(dm_descriptor_t desc, char **name)
505 * INPUT: desc - a dm_descriptor_t handle for a device
506 * name - a char * name
508 * OUTPUT: **name - a pointer to a char * to hold the display
509 * name associated with the input descriptor.
511 * RETURNS: int - 0 on success
512 * !0 otherwise.
514 * PURPOSE: Helpers to set/get the input descriptor's display name.
516 * Only slices, disks and HBAs should have display names.
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.
522 * An entry is added in the name->descriptor cache
523 * so the descriptor can be found by name quickly.
526 set_display_name(
527 dm_descriptor_t desc,
528 char *name)
530 nvlist_t *attrs = NULL;
531 int error = 0;
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));
537 return (error);
541 get_display_name(
542 dm_descriptor_t desc,
543 char **name)
545 nvlist_t *attrs = NULL;
546 int error = 0;
548 ((error = get_cached_attributes(desc, &attrs)) != 0) ||
549 (error = get_string(attrs, ATTR_DEV_CTD_NAME, name));
551 return (error);
555 * FUNCTION: disk_get_slices(dm_descriptor_t disk, dlist_t **list)
557 * INPUT: disk - a dm_descriptor_t handle for a disk
559 * OUTPUT: *list - a pointer to list to hold the results.
561 * RETURNS: int - 0 on success
562 * !0 otherwise.
564 * PURPOSE: Collect all of the known slices for the input disk.
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.
571 disk_get_slices(
572 dm_descriptor_t disk,
573 dlist_t **list)
575 dm_descriptor_t *media = NULL;
576 boolean_t virtual = B_FALSE;
577 int i = 0;
578 int error = 0;
580 *list = 0;
582 if ((error = disk_has_virtual_slices(disk, &virtual)) != 0) {
583 return (error);
586 if (virtual == B_TRUE) {
587 error = disk_get_virtual_slices(disk, list);
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);
594 if (error == 0) {
595 /* if there's no media, this is a removeable drive */
596 if (media != NULL && *media != NULL) {
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);
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);
616 free(slices);
618 free(media);
620 } else {
621 print_get_assoc_desc_error(disk, gettext("media"), error);
624 return (error);
628 get_virtual_slices(
629 dlist_t **list)
631 *list = _virtual_slices;
633 return (0);
637 * FUNCTION: virtual_repartition_drive(dm_descriptor_t disk,
638 * mdvtoc_t *vtocp)
640 * INPUT: disk - the disk to be virtually repartitioned
642 * OUTPUT: vtocp - a poitner to a mdvtoc struct to hold the results
644 * RETURNS: int - 0 on success
645 * !0 otherwise.
647 * PURPOSE: Helper which emulates the repartitioning that is done
648 * when a disk is added to a diskset.
650 * Modified version of meta_partition_drive which uses info
651 * from libdiskmgt to accomplish the repartitioning.
653 * This exists to allow the layout module to run with a
654 * simulated hardware environment.
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.
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.
673 static int
674 virtual_repartition_drive(
675 dm_descriptor_t disk,
676 mdvtoc_t *vtocp)
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;
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;
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.
700 ressize = MD_DBSIZE + VTOC_SIZE;
701 resflag = V_UNMNT;
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);
711 if (efi) {
712 replicaslice = 6;
716 * Both cylsize and drvsize are in units of disk sectors.
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.
727 cylsize = ((unsigned long long)nheads) * nsects;
728 drvsize = cylsize * ncyls;
731 * How many cylinders must we reserve for slice seven to
732 * ensure that it meets the previously calculated minimum
733 * size?
735 reservedcyl = (ressize + cylsize - 1) / cylsize;
738 * It seems unlikely that someone would pass us too small a
739 * disk, but it's still worth checking for...
741 if (reservedcyl >= ncyls) {
742 volume_set_error(
743 gettext("disk is too small to hold a metadb replica"));
744 return (-1);
747 replica_start = 0;
748 replica_size = reservedcyl * cylsize;
749 data_start = reservedcyl * cylsize;
750 data_size = drvsize - (reservedcyl * cylsize);
753 * fill in the proposed VTOC information.
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;
766 return (0);
770 * FUNCTION: create_virtual_slices(dlist_t *disks)
772 * INPUT: possibles - a list of dm_descriptor_t disk handles for
773 * disks known to be available for use by layout.
775 * SIDEEFFECT: populates the private of virtual slices.
777 * RETURNS: int - 0 on success
778 * !0 otherwise.
780 * PURPOSE: Helper which creates virtual slices for each disk which
781 * could be added to a diskset if necessary...
783 * Iterate the input list of available disks and see what the
784 * slicing would be if the disk were added to a diskset.
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.
791 create_virtual_slices(
792 dlist_t *disks)
794 int error = 0;
795 dlist_t *iter;
796 boolean_t sim = B_FALSE;
797 static char *simfile = "METASSISTSIMFILE";
799 sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0));
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) {
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;
810 if ((error = get_display_name(disk, &dname)) != 0) {
811 break;
814 if (sim != B_TRUE) {
816 /* sim disabled: use meta_repartition_drive() */
818 md_error_t mderror = mdnullerror;
819 int opts = (MD_REPART_FORCE | MD_REPART_DONT_LABEL);
820 mdsetname_t *sp;
821 mddrivename_t *dnp;
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;
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;
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;
849 } else {
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;
861 /* BEGIN CSTYLED */
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
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));
876 dlist_free_items(slices, NULL);
879 /* scan VTOC, find slice with the free space */
880 for (i = 0; i < vtoc.nparts; i++) {
882 if (vtoc.parts[i].tag == V_USR &&
883 vtoc.parts[i].flag != V_UNMNT) {
885 /* non-replica slice with free space */
886 char buf[MAXPATHLEN];
887 (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i);
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;
897 } else if (vtoc.parts[i].tag == V_RESERVED) {
899 /* skip EFI reserved slice */
900 continue;
902 } else if (vtoc.parts[i].tag == V_USR &&
903 vtoc.parts[i].flag == V_UNMNT) {
905 /* BEGIN CSTYLED */
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.
911 * XXX this is a temporary workaround until
912 * 4712873 is integrated...
914 /* BEGIN CSTYLED */
915 char buf[MAXPATHLEN];
916 (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i);
917 add_slice_to_remove(buf, i);
919 /* replica slice, stop here */
920 break;
925 return (error);
929 * FUNCTION: add_virtual_slice(char *name, uint32_t index,
930 * uint64_t startblk, uint64_t sizeblks,
931 * dm_descriptor_t disk)
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 ...
939 * RETURNS: int - 0 on success
940 * !0 otherwise.
942 * PURPOSE: Helper which adds the appropriate data structures to
943 * represent a new virtual slice.
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.
954 add_virtual_slice(
955 char *name,
956 uint32_t index,
957 uint64_t startblk,
958 uint64_t sizeblks,
959 dm_descriptor_t disk)
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;
968 if ((error = nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0)) != 0) {
969 return (error);
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)) ||
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)) ||
986 /* add attributes to the cache */
987 (error = get_name(sp, &sname)) ||
988 (error = add_cached_attributes(sname, attrs)) ||
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));
995 if (error != 0) {
996 return (error);
999 /* generate slice's aliases if the disk has aliases */
1000 if (aliases != NULL) {
1001 char buf[MAXNAMELEN];
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);
1008 dlist_free_items(aliases, free);
1011 if ((item = dlist_new_item((void *)(uintptr_t)sp)) == NULL) {
1012 return (ENOMEM);
1015 _virtual_slices = dlist_append(item, _virtual_slices, AT_HEAD);
1017 oprintf(OUTPUT_DEBUG,
1018 gettext(" created virtual slice %s start: %llu, size: %llu\n"),
1019 sname, startblk, sizeblks);
1021 return (error);
1025 * FUNCTION: release_virtual_slices()
1027 * PURPOSE: Helper which cleans up the module private list of virtual
1028 * slices.
1030 * The descriptors for the virtual slices are cleaned up
1031 * in device_cache_util.free_cached_descriptors
1033 void
1034 release_virtual_slices()
1036 dlist_free_items(_virtual_slices, NULL);
1037 _virtual_slices = NULL;
1041 * FUNCTION: disk_add_virtual_slice(dm_descriptor_t disk,
1042 * dm_descriptor_t slice)
1044 * INPUT: disk - a dm_descriptor_t disk handle
1045 * slice - a dm_descriptor_t virtual slice handle
1047 * RETURNS: int - 0 on success
1048 * !0 otherwise
1050 * PURPOSE: Helper which adds a virtual slice to the input disk's
1051 * list of virtual slices.
1053 * The disk's virtual slice dm_descriptor_t handles are
1054 * stored in the disk's nvpair attribute list.
1056 static int
1057 disk_add_virtual_slice(
1058 dm_descriptor_t disk,
1059 dm_descriptor_t slice)
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;
1068 if ((error = get_cached_attributes(disk, &attrs)) != 0) {
1069 return (error);
1072 if ((error = get_uint64_array(
1073 attrs, ATTR_VIRTUAL_SLICES, &old_slices, &nelem)) != 0) {
1074 if (error != ENOENT) {
1075 return (error);
1077 error = 0;
1080 /* make a new array */
1081 new_slices = (uint64_t *)calloc(nelem + 1, sizeof (uint64_t));
1082 if (new_slices != NULL) {
1084 for (i = 0; i < nelem; i++) {
1085 new_slices[i] = old_slices[i];
1087 new_slices[i] = slice;
1089 error = set_uint64_array(
1090 attrs, ATTR_VIRTUAL_SLICES, new_slices, nelem);
1092 free(new_slices);
1094 } else {
1095 error = ENOMEM;
1098 return (error);
1102 * FUNCTION: disk_has_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
1104 * INPUT: disk - a dm_descriptor_t disk handle
1106 * OUTPUT: bool - B_TRUE - if the disk has virtual slices
1107 * B_FALSE - otherwise
1109 * RETURNS: int - 0 on success
1110 * !0 otherwise
1112 * PURPOSE: Helper which determines if the input disk has virtual slices.
1114 * If a disk has virtual slices, their dm_descriptor_t handles
1115 * will be stored in the disk's nvpair attribute list.
1117 static int
1118 disk_has_virtual_slices(
1119 dm_descriptor_t disk,
1120 boolean_t *bool)
1122 nvlist_t *attrs = NULL;
1123 uint64_t *slices = NULL;
1124 uint_t nelem = 0;
1125 int error = 0;
1127 *bool = B_FALSE;
1129 if ((error = get_cached_attributes(disk, &attrs)) != 0) {
1130 return (error);
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;
1146 nelem = i;
1150 *bool = (nelem != 0);
1152 return (error);
1156 * FUNCTION: disk_get_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
1158 * INPUT: disk - a dm_descriptor_t disk handle
1160 * OUTPUT: list - a dlist_t list of dm_descriptor_t handles for the
1161 * disk's virtual slices.
1163 * RETURNS: int - 0 on success
1164 * !0 otherwise
1166 * PURPOSE: Helper which retrieves a list of the input disk's virtual
1167 * slices.
1169 * If a disk has virtual slices, their dm_descriptor_t handles
1170 * will be stored in the disk's nvpair attribute list.
1172 static int
1173 disk_get_virtual_slices(
1174 dm_descriptor_t disk,
1175 dlist_t **list)
1177 nvlist_t *attrs = NULL;
1178 uint64_t *slices = NULL;
1179 uint_t nelem = 0;
1180 int error = 0;
1181 int i = 0;
1183 if ((error = get_cached_attributes(disk, &attrs)) != 0) {
1184 return (error);
1187 if ((error = get_uint64_array(
1188 attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) {
1189 if (error != ENOENT) {
1190 return (error);
1193 return (0);
1196 for (i = 0; i < nelem && slices[i] != -1; i++) {
1197 dlist_t *item = NULL;
1199 if ((item = dlist_new_item((void*)(uintptr_t)slices[i])) == NULL) {
1200 error = ENOMEM;
1201 break;
1204 *list = dlist_append(item, *list, AT_TAIL);
1207 return (error);
1211 * FUNCTION: is_virtual_slice(dm_descriptor_t desc)
1213 * INPUT: desc - a dm_descriptor_t handle
1215 * RETURNS: boolean_t - B_TRUE if the input descriptor is for
1216 * a virtual slice.
1217 * B_FALSE otherwise
1219 * PURPOSE: Helper which determines whether the input descriptor
1220 * corresponds to a virtual slice.
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.
1226 boolean_t
1227 is_virtual_slice(
1228 dm_descriptor_t desc)
1230 return (dlist_contains(_virtual_slices,
1231 (void*)(uintptr_t)desc, compare_descriptors));
1235 * FUNCTION: disk_get_available_slice_index(dm_descriptor_t disk,
1236 * uint32_t *newindex)
1238 * INPUT: disk - a dm_descriptor_t handle for a disk
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.
1244 * RETURNS: int - 0 on success
1245 * !0 otherwise.
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.
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.
1256 * V_NUMPAR is used as the number of available slices,
1257 * SPARC systems have V_NUMPAR == 8, X86 have V_NUMPAR == 16.
1259 * EFI disks have only 7.
1262 disk_get_available_slice_index(
1263 dm_descriptor_t disk,
1264 uint32_t *newindex)
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;
1276 if (((error = disk_get_slices(disk, &slices)) != 0) ||
1277 (error = disk_get_is_efi(disk, &is_efi)) != 0) {
1278 return (error);
1281 if (is_efi == B_TRUE) {
1282 /* limit possible indexes to 7 for EFI */
1283 nslices = 7;
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);
1294 /* eliminate indexes that are reserved */
1295 if ((error = disk_get_reserved_indexes(disk, &reserved)) != 0) {
1296 return (error);
1299 if (reserved != NULL) {
1300 for (i = 0; i < nslices; i++) {
1301 if (reserved[i] == 1) {
1302 used[i] = B_TRUE;
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;
1313 ((error = slice_get_index(sp, &index)) != 0) ||
1314 (error = slice_get_size_in_blocks(sp, &size));
1315 if (error != 0) {
1316 return (error);
1319 if (size > 0) {
1320 used[(int)index] = B_TRUE;
1323 dlist_free_items(slices, NULL);
1325 for (i = 0; i < nslices; i++) {
1327 /* skip the index passed in */
1328 if (i == *newindex) {
1329 continue;
1332 if (used[i] != B_TRUE) {
1333 index = i;
1334 break;
1338 if (i != nslices) {
1339 /* return unused slice index */
1340 *newindex = index;
1343 free((void *)used);
1345 return (0);
1349 * FUNCTION: disk_get_media_type(dm_descriptor_t slice, uint32_t *type)
1351 * INPUT: slice - a dm_descriptor_t handle for a disk
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.
1357 * RETURNS: int - 0 on success
1358 * !0 otherwise.
1360 * PURPOSE: Retrieves the media type for the disk.
1362 * Get the media associate with the input disk descriptor
1363 * and determine its type.
1366 disk_get_media_type(
1367 dm_descriptor_t disk,
1368 uint32_t *type)
1370 int error = 0;
1371 dm_descriptor_t *mdp = NULL;
1373 mdp = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1374 (void) add_descriptors_to_free(mdp);
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);
1386 nvlist_free(attrs);
1388 /* no media: removeable drive */
1391 if (mdp != NULL) {
1392 free(mdp);
1395 return (error);
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)
1412 * INPUT: disk - a dm_descriptor_t handle for a disk
1414 * OUTPUT: *bool - a pointer to a variable of the appropriate
1415 * type to hold the current value for the attribute
1416 * of interest.
1418 * RETURNS: int - 0 on success
1419 * !0 otherwise.
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.
1425 static int
1426 disk_get_rpm(
1427 dm_descriptor_t disk,
1428 uint32_t *val)
1430 uint64_t val64 = 0;
1431 int error = 0;
1433 if ((error = disk_get_uint64_attribute(
1434 disk, DM_RPM, &val64)) != 0) {
1435 return (error);
1438 *val = (uint32_t)val64;
1440 return (error);
1444 disk_get_drive_type(
1445 dm_descriptor_t disk,
1446 uint32_t *val)
1448 uint64_t val64 = 0;
1449 int error = 0;
1451 if ((error = disk_get_uint64_attribute(
1452 disk, DM_DRVTYPE, &val64)) != 0) {
1453 return (error);
1456 *val = (uint32_t)val64;
1458 return (error);
1461 static int
1462 disk_get_sync_speed(
1463 dm_descriptor_t disk,
1464 uint32_t *val)
1466 uint64_t val64 = 0;
1467 int error = 0;
1469 if ((error = disk_get_uint64_attribute(
1470 disk, DM_SYNC_SPEED, &val64)) != 0) {
1471 return (error);
1474 *val = (uint32_t)val64;
1476 return (error);
1479 /* returns number of usable blocks */
1481 disk_get_size_in_blocks(
1482 dm_descriptor_t disk,
1483 uint64_t *val)
1485 return (disk_get_uint64_attribute(disk, DM_NACCESSIBLE, val));
1488 /* returns first usable block on disk */
1490 disk_get_start_block(
1491 dm_descriptor_t disk,
1492 uint64_t *val)
1494 return (disk_get_uint64_attribute(disk, DM_START, val));
1498 disk_get_blocksize(
1499 dm_descriptor_t disk,
1500 uint64_t *val)
1502 return (disk_get_uint64_attribute(disk, DM_BLOCKSIZE, val));
1506 disk_get_ncylinders(
1507 dm_descriptor_t disk,
1508 uint64_t *val)
1510 return (disk_get_uint64_attribute(disk, DM_NCYLINDERS, val));
1514 disk_get_nheads(
1515 dm_descriptor_t disk,
1516 uint64_t *val)
1518 return (disk_get_uint64_attribute(disk, DM_NHEADS, val));
1522 disk_get_nsectors(
1523 dm_descriptor_t disk,
1524 uint64_t *val)
1526 return (disk_get_uint64_attribute(disk, DM_NSECTORS, val));
1530 * FUNCTION: disk_get_is_online(dm_descriptor_t disk, boolean_t *val)
1532 * INPUT: disk - a dm_descriptor_t handle for a disk
1534 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1536 * RETURNS: int - 0 on success
1537 * !0 otherwise.
1539 * PURPOSE: Determine if the input disk is "online".
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.
1545 disk_get_is_online(
1546 dm_descriptor_t disk,
1547 boolean_t *val)
1549 uint64_t status = 0;
1550 int error = 0;
1552 *val = B_FALSE;
1554 error = disk_get_uint64_attribute(disk, DM_STATUS, &status);
1555 if (error == 0) {
1556 *val = (status == 1) ? B_TRUE : B_FALSE;
1559 return (error);
1563 * FUNCTION: disk_get_is_efi(dm_descriptor_t disk, boolean_t *bool)
1565 * INPUT: disk - a dm_descriptor_t handle for a disk
1567 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1569 * RETURNS: int - 0 on success
1570 * !0 otherwise.
1572 * PURPOSE: Determine if the input disk is labeled with an EFI label.
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.
1579 disk_get_is_efi(
1580 dm_descriptor_t disk,
1581 boolean_t *bool)
1583 return (disk_get_boolean_attribute(disk, DM_EFI, bool));
1587 * FUNCTION: disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *bool)
1589 * INPUT: disk - a dm_descriptor_t handle for a disk
1591 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1593 * RETURNS: int - 0 on success
1594 * !0 otherwise.
1596 * PURPOSE: Determine if the input disk has an FDISK partition.
1599 disk_get_has_fdisk(
1600 dm_descriptor_t disk,
1601 boolean_t *bool)
1603 return (disk_get_boolean_attribute(disk, DM_FDISK, bool));
1607 * FUNCTION: disk_get_has_solaris_partition(dm_descriptor_t disk, boolean_t *bool)
1609 * INPUT: disk - a dm_descriptor_t handle for a disk
1611 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1613 * RETURNS: int - 0 on success
1614 * !0 otherwise.
1616 * PURPOSE: Determine if the input disk has a Solaris FDISK partition.
1619 disk_get_has_solaris_partition(
1620 dm_descriptor_t disk,
1621 boolean_t *bool)
1623 boolean_t has_fdisk = B_FALSE;
1624 int error = 0;
1626 if ((error = disk_get_has_fdisk(disk, &has_fdisk)) != 0) {
1627 return (error);
1630 *bool = B_FALSE;
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;
1662 nvlist_free(attrs);
1666 free(parts);
1667 free(media);
1670 /* if there was no media, it was a removeable drive */
1673 return (error);
1676 static int
1677 disk_get_boolean_attribute(
1678 dm_descriptor_t disk,
1679 char *attr,
1680 boolean_t *bool)
1682 nvlist_t *attrs = NULL;
1683 int error = 0;
1685 *bool = B_FALSE;
1687 if ((strcmp(attr, DM_EFI) == 0) ||
1688 (strcmp(attr, DM_FDISK) == 0)) {
1691 * these attributes are actually on the media,
1692 * not the disk... so get the media descriptor
1693 * for this disk
1695 dm_descriptor_t *media;
1697 media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1698 (void) add_descriptors_to_free(media);
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);
1706 free(media);
1708 } else {
1709 error = get_cached_attributes(disk, &attrs);
1710 if (error != 0) {
1711 print_get_desc_attr_error(disk, gettext("drive"), attr, error);
1715 if (error != 0) {
1716 return (error);
1719 if (nvlist_lookup_boolean(attrs, attr) == 0) {
1720 *bool = B_TRUE;
1723 return (error);
1726 static int
1727 disk_get_uint64_attribute(
1728 dm_descriptor_t disk,
1729 char *attr,
1730 uint64_t *val)
1732 nvlist_t *attrs = NULL;
1733 uint32_t ui32 = 0;
1734 int error = 0;
1737 * these attributes are actually on the media,
1738 * not the disk... so get the media descriptor
1739 * for this disk
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)) {
1749 dm_descriptor_t *media;
1751 media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
1752 (void) add_descriptors_to_free(media);
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);
1764 } else {
1765 error = get_cached_attributes(disk, &attrs);
1766 if (error != 0) {
1767 print_get_desc_attr_error(disk, gettext("drive"), attr, error);
1771 if (error != 0) {
1772 return (error);
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;
1791 return (error);
1795 * FUNCTION: group_similar_hbas(dlist_t *hbas, dlist_t **list)
1797 * INPUT: hbas - a list of HBA dm_descriptor_t handles.
1799 * OUTPUT: **list - a pointer to a list to hold the lists of HBAs
1800 * grouped by characteristics.
1802 * RETURNS: int - 0 on success
1803 * !0 otherwise.
1805 * PURPOSE: Examine the input HBAs and collate them into separate
1806 * lists, grouped by their type and the protocols they
1807 * support.
1809 * The returned list of list is arranged in decreasing order
1810 * of preference, "better" HBAs come first.
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
1823 group_similar_hbas(
1824 dlist_t *hbas,
1825 dlist_t **list)
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
1844 dlist_t *groups = NULL;
1845 dlist_t *iter = NULL;
1846 dlist_t *item = NULL;
1847 dlist_t *lists[HBA_LAST];
1849 int error = 0;
1850 int i = 0;
1852 (void) memset(lists, '\0', HBA_LAST * sizeof (dlist_t *));
1854 for (iter = hbas;
1855 (iter != NULL) && (error == 0);
1856 iter = iter->next) {
1858 dm_descriptor_t hba = (uintptr_t)iter->obj;
1859 char *type = NULL;
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;
1867 if ((error = hba_get_type(hba, &type)) != 0) {
1868 free(item);
1869 continue;
1872 if (strcmp(type, DM_CTYPE_FIBRE) == 0) {
1874 boolean_t ismpxio = B_FALSE;
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);
1886 } else {
1887 free(item);
1890 } else if (strcmp(type, DM_CTYPE_SCSI) == 0) {
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;
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));
1905 if (error == 0) {
1907 if (ismpxio) {
1909 lists[HBA_SCSI_MPXIO] =
1910 dlist_append(item,
1911 lists[HBA_SCSI_MPXIO], AT_TAIL);
1913 } else if (is80) {
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);
1925 } else if (is40) {
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);
1937 } else if (is20) {
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);
1949 } else {
1950 lists[HBA_SCSI] =
1951 dlist_append(item, lists[HBA_SCSI], AT_TAIL);
1954 } else {
1955 free(item);
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);
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);
1984 if (error != 0) {
1985 for (i = 0; i < HBA_LAST; i++) {
1986 dlist_free_items(lists[i], NULL);
1987 lists[i] = NULL;
1990 if (groups != NULL) {
1991 dlist_free_items(groups, NULL);
1995 *list = groups;
1997 return (error);
2001 * FUNCTION: hba_group_usable_disks(dm_descriptor_t hba, dlist_t **list)
2003 * INPUT: hba - a dm_descriptor_t handle for a slice
2005 * OUTPUT: **list - a pointer to a list to hold the lists of disks
2006 * grouped by characteristics.
2008 * RETURNS: int - 0 on success
2009 * !0 otherwise.
2011 * PURPOSE: Examine the disks assocated with the HBA and collates them
2012 * into separate lists, grouped by similar characteristics.
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
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.
2026 hba_group_usable_disks(
2027 dm_descriptor_t hba,
2028 dlist_t **list)
2030 dm_descriptor_t *disk = NULL;
2031 char *name = NULL;
2032 int i = 0;
2033 int error = 0;
2035 disk = dm_get_associated_descriptors(hba, DM_DRIVE, &error);
2036 (void) add_descriptors_to_free(disk);
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;
2046 for (i = 0; (disk[i] != NULL) && (error == 0); i++) {
2048 uint32_t dtype = DM_DT_UNKNOWN;
2049 dlist_t *usable = NULL;
2051 /* ignore non fixed media drives */
2052 if (((error = disk_get_drive_type(disk[i], &dtype)) != 0) ||
2053 (dtype != DM_DT_FIXED)) {
2054 continue;
2057 if (dlist_contains(usable, &disk[i],
2058 compare_descriptor_names) == B_TRUE) {
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;
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;
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);
2085 /* add to the appropriate list */
2089 if (disk != NULL) {
2090 free(disk);
2093 return (error);
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)
2100 * INPUT: hba - a dm_descriptor_t handle for a slice
2102 * OUTPUT: *val - a pointer to a uint16_t to hold the current number
2103 * of available disks for the input HBA.
2105 * RETURNS: int - 0 on success
2106 * !0 otherwise.
2109 hba_set_n_avail_disks(
2110 dm_descriptor_t hba,
2111 uint16_t val)
2113 nvlist_t *attrs;
2114 int error = 0;
2116 ((error = get_cached_attributes(hba, &attrs)) != 0) ||
2117 (error = set_uint16(attrs, ATTR_HBA_N_DISKS, val));
2119 return (error);
2123 hba_get_n_avail_disks(
2124 dm_descriptor_t hba,
2125 uint16_t *val)
2127 nvlist_t *attrs;
2128 int error = 0;
2130 *val = 0;
2132 ((error = get_cached_attributes(hba, &attrs)) != 0) ||
2133 (error = get_uint16(attrs, ATTR_HBA_N_DISKS, val));
2135 return (error);
2139 * FUNCTION: hba_get_type(dm_descriptor_t hba, char **type)
2141 * INPUT: hba - a dm_descriptor_t handle for a HBA
2143 * OUTPUT: **type - a char * to hold the current type value for
2144 * the HBA.
2146 * RETURNS: int - 0 on success
2147 * !0 otherwise.
2149 * PURPOSE: Retrieves the type attribute for the HBA.
2152 hba_get_type(
2153 dm_descriptor_t hba,
2154 char **type)
2156 nvlist_t *attrs;
2157 int error = 0;
2159 *type = NULL;
2161 ((error = get_cached_attributes(hba, &attrs)) != 0) ||
2162 (error = get_string(attrs, DM_CTYPE, type));
2164 return (error);
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)
2175 * INPUT: hba - a dm_descriptor_t handle for a HBA
2177 * OUTPUT: *bool - a pointer to a boolean_t to hold the
2178 * boolean value of the predicate.
2180 * RETURNS: int - 0 on success
2181 * !0 otherwise.
2183 * PURPOSE: Wrappers around hba_supports_protocol which determines
2184 * if the input HBA supports the protocol of interest.
2187 hba_is_fast(
2188 dm_descriptor_t hba,
2189 boolean_t *bool)
2191 return (hba_supports_protocol(hba, DM_FAST, bool));
2195 hba_is_fast_20(
2196 dm_descriptor_t hba,
2197 boolean_t *bool)
2199 return (hba_supports_protocol(hba, DM_FAST20, bool));
2203 hba_is_fast_40(
2204 dm_descriptor_t hba,
2205 boolean_t *bool)
2207 return (hba_supports_protocol(hba, DM_FAST40, bool));
2211 hba_is_fast_80(
2212 dm_descriptor_t hba,
2213 boolean_t *bool)
2215 return (hba_supports_protocol(hba, DM_FAST80, bool));
2219 hba_is_multiplex(
2220 dm_descriptor_t hba,
2221 boolean_t *bool)
2223 return (hba_supports_protocol(hba, DM_MULTIPLEX, bool));
2227 hba_supports_wide(
2228 dm_descriptor_t hba,
2229 boolean_t *bool)
2231 nvlist_t *attrs = NULL;
2232 int error = 0;
2234 *bool = B_FALSE;
2236 if ((error = get_cached_attributes(hba, &attrs)) != 0) {
2237 return (error);
2240 *bool = (0 == nvlist_lookup_boolean(attrs, DM_WIDE));
2242 return (error);
2246 * FUNCTION: hba_supports_protocol(dm_descriptor_t hba, char *attr,
2247 * boolean_t *bool)
2249 * INPUT: hba - a dm_descriptor_t handle for a HBA
2250 * attr - a protocol "name"
2252 * OUTPUT: *bool - a pointer to a boolean_t to hold the
2253 * boolean value of the predicate.
2255 * RETURNS: int - 0 on success
2256 * !0 otherwise.
2258 * PURPOSE: Checks the HBAs attributes to see if it is known to
2259 * support the protocol of interest.
2261 * If the protocol is supported, it will have an entry
2262 * in the nvpair attribute list that can be retrieved.
2264 * If the entry cannot be retrieved, the protocol is not
2265 * supported.
2268 hba_supports_protocol(
2269 dm_descriptor_t hba,
2270 char *attr,
2271 boolean_t *bool)
2273 nvlist_t *attrs = NULL;
2274 int error = 0;
2276 *bool = B_FALSE;
2278 if ((error = get_cached_attributes(hba, &attrs)) != 0) {
2279 return (error);
2282 *bool = (0 == nvlist_lookup_boolean(attrs, attr));
2284 return (error);
2288 * FUNCTION: slice_set_size(dm_descriptor_t slice, uint64_t size)
2290 * INPUT: slice - a dm_descriptor_t handle for a slice
2292 * OUTPUT: size - a uint64_t value representing the size of the
2293 * slice.
2295 * RETURNS: int - 0 on success
2296 * !0 otherwise.
2298 * PURPOSE: Wrapper around slice_set_uint64_attribute which converts
2299 * the input size in bytes to blocks prior to storing it.
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.
2306 slice_set_size(
2307 dm_descriptor_t slice,
2308 uint64_t size)
2310 dm_descriptor_t disk = NULL;
2311 uint64_t blksize = 0;
2312 int error = 0;
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)));
2318 return (error);
2322 * FUNCTION: slice_set_size_in_blocks(dm_descriptor_t slice, uint64_t size)
2324 * INPUT: slice - a dm_descriptor_t handle for a slice
2326 * OUTPUT: size - a uint64_t value representing the size of the
2327 * slice.
2329 * RETURNS: int - 0 on success
2330 * !0 otherwise.
2332 * PURPOSE: Wrapper around slice_set_uint64_attribute to set the slice
2333 * size.
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.
2340 slice_set_size_in_blocks(
2341 dm_descriptor_t slice,
2342 uint64_t size)
2344 return (slice_set_attribute(slice, DM_SIZE, size));
2348 * FUNCTION: slice_set_start_block(dm_descriptor_t slice, uint64_t start)
2350 * INPUT: slice - a dm_descriptor_t handle for a slice
2352 * OUTPUT: size - a uint64_t value representing the start block of the
2353 * slice.
2355 * RETURNS: int - 0 on success
2356 * !0 otherwise.
2358 * PURPOSE: Wrapper around slice_set_attribute.
2360 * This function is used when an existing slice gets adjusted
2361 * due to being resized or combined with another slice.
2364 slice_set_start_block(
2365 dm_descriptor_t slice,
2366 uint64_t start)
2368 return (slice_set_attribute(slice, DM_START, start));
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)
2378 * INPUT: slice - a dm_descriptor_t handle for a slice
2380 * OUTPUT: *val - a pointer to a uint64_t to hold the
2381 * current value of the desired attribute.
2383 * RETURNS: int - 0 on success
2384 * !0 otherwise.
2386 * PURPOSE: Wrappers around slice_get_uint64_attribute which retrieve
2387 * specific attribute values.
2390 slice_get_start_block(
2391 dm_descriptor_t slice,
2392 uint64_t *val)
2394 return (slice_get_uint64_attribute(slice, DM_START, val));
2398 slice_get_size_in_blocks(
2399 dm_descriptor_t slice,
2400 uint64_t *val)
2402 return (slice_get_uint64_attribute(slice, DM_SIZE, val));
2406 slice_get_start(
2407 dm_descriptor_t slice,
2408 uint64_t *val)
2410 dm_descriptor_t disk = NULL;
2411 uint64_t blksize = 0;
2412 uint64_t nblks = 0;
2413 int error = 0;
2415 ((error = slice_get_disk(slice, &disk)) != 0) ||
2416 (error = disk_get_blocksize(disk, &blksize)) ||
2417 (error = slice_get_start_block(slice, &nblks));
2419 if (error == 0) {
2420 *val = (blksize * nblks);
2423 return (error);
2427 slice_get_size(
2428 dm_descriptor_t slice,
2429 uint64_t *val)
2431 dm_descriptor_t disk = NULL;
2432 uint64_t blksize = 0;
2433 uint64_t nblks = 0;
2434 int error = 0;
2436 *val = 0;
2438 ((error = slice_get_disk(slice, &disk)) != 0) ||
2439 (error = slice_get_size_in_blocks(slice, &nblks)) ||
2440 (error = disk_get_blocksize(disk, &blksize));
2442 if (error == 0) {
2443 *val = (blksize * nblks);
2446 return (error);
2450 slice_get_index(
2451 dm_descriptor_t slice,
2452 uint32_t *val)
2454 uint64_t index = 0;
2455 int error = 0;
2457 if ((error = slice_get_uint64_attribute(
2458 slice, DM_INDEX, &index)) != 0) {
2459 return (error);
2462 *val = (uint32_t)index;
2464 return (0);
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)
2473 * INPUT: slice - a dm_descriptor_t handle for a slice
2474 * attr - a char * attribute name
2475 * val - auint64_t value
2477 * OUTPUT: *val - a pointer to a uint64_t to hold the
2478 * current value of the named attribute.
2480 * RETURNS: int - 0 on success
2481 * !0 otherwise.
2483 * PURPOSE: Helpers to set/get the value for a slice's attribute.
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.
2490 static int
2491 slice_get_uint64_attribute(
2492 dm_descriptor_t slice,
2493 char *attr,
2494 uint64_t *val)
2496 nvlist_t *attrs = NULL;
2497 uint32_t ui32 = 0;
2498 int error = 0;
2500 if ((error = get_cached_attributes(slice, &attrs)) != 0) {
2501 return (error);
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);
2515 if (error != 0) {
2516 print_get_desc_attr_error(slice, "slice", attr, error);
2519 return (error);
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.
2527 static int
2528 slice_set_attribute(
2529 dm_descriptor_t slice,
2530 char *attr,
2531 uint64_t val)
2533 nvlist_t *attrs = NULL;
2534 int error = 0;
2536 if ((error = get_cached_attributes(slice, &attrs)) != 0) {
2537 return (error);
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);
2550 if (error != 0) {
2551 print_set_desc_attr_error(slice, "slice", attr, error);
2554 return (error);
2558 * FUNCTION: virtual_slice_get_disk(dm_descriptor_t slice,
2559 * dm_descriptor_t *diskp)
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
2565 * OUTPUT: the disk associated with the virtual slice.
2567 * RETURNS: int - 0 on success
2568 * !0 otherwise
2570 * PURPOSE: Helper which determines the disk that the input virtual
2571 * slice "belongs" to.
2573 * The virtual slice's disk is stored in the slice's nvpair
2574 * attribute list when the slice gets created.
2576 static int
2577 virtual_slice_get_disk(
2578 dm_descriptor_t slice,
2579 dm_descriptor_t *diskp)
2581 uint64_t disk = 0;
2582 int error = 0;
2584 if ((error = slice_get_uint64_attribute(
2585 slice, ATTR_DISK_FOR_SLICE, &disk)) != 0) {
2586 return (error);
2589 *diskp = (dm_descriptor_t)disk;
2591 if (disk == 0) {
2592 print_get_desc_attr_error(slice, "virtual slice", "disk", error);
2593 return (-1);
2596 return (0);
2600 * FUNCTION: slice_get_disk(dm_descriptor_t disk, dm_descriptor_t *diskp)
2602 * INPUT: slice - a dm_descriptor_t handle for a slice
2604 * OUTPUT: diskp - a pointer to a dm_descriptor_t to hold the
2605 * disk associated with the input slice
2607 * RETURNS: int - 0 on success
2608 * !0 otherwise.
2610 * PURPOSE: Helper which retrieves the disk for a slice device.
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.
2619 slice_get_disk(
2620 dm_descriptor_t slice,
2621 dm_descriptor_t *diskp)
2623 dm_descriptor_t *media = NULL;
2625 int i = 0;
2626 int error = 0;
2628 *diskp = 0;
2630 if (is_virtual_slice(slice)) {
2631 return (virtual_slice_get_disk(slice, diskp));
2634 media = dm_get_associated_descriptors(slice, DM_MEDIA, &error);
2635 (void) add_descriptors_to_free(media);
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;
2644 if (error != 0) {
2645 return (error);
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);
2655 if ((error == 0) && (disks != NULL) && (disks[0] != NULL)) {
2656 *diskp = disks[0];
2658 free(disks);
2661 if (media != NULL) {
2662 free(media);
2665 if (*diskp == 0) {
2666 print_get_desc_attr_error(slice,
2667 gettext("slice"), gettext("disk"), ENODEV);
2668 error = -1;
2671 return (error);
2675 * FUNCTION: slice_get_hbas(dm_descriptor_t slice, dlist_t **list)
2677 * INPUT: slice - a dm_descriptor_t handle for a slice
2679 * OUTPUT: list - a pointer to a dlist_t list to hold the
2680 * HBAs associated with the input slice
2682 * RETURNS: int - 0 on success
2683 * !0 otherwise.
2685 * PURPOSE: Helper which retrieves the known HBAs for a slice device.
2689 slice_get_hbas(
2690 dm_descriptor_t slice,
2691 dlist_t **list)
2693 dm_descriptor_t disk = NULL;
2694 int error = 0;
2696 *list = NULL;
2698 ((error = slice_get_disk(slice, &disk)) != 0) ||
2699 (error = disk_get_hbas(disk, list));
2701 if (*list == NULL) {
2702 print_get_desc_attr_error(slice, "slice", "HBA", ENODEV);
2703 error = -1;
2706 return (error);
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)
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
2718 * OUTPUT: list - a pointer to a dlist_t list to hold the
2719 * objects associated with the input disk
2721 * RETURNS: int - 0 on success
2722 * !0 otherwise.
2724 * PURPOSE: Helper which retrieves the associated objects of the
2725 * requested type for a disk device.
2727 static int
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)
2734 int i = 0;
2735 int error = 0;
2737 dm_descriptor_t *assoc =
2738 dm_get_associated_descriptors(disk, assoc_type, &error);
2740 (void) add_descriptors_to_free(assoc);
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);
2753 } else {
2754 print_get_assoc_desc_error(disk, assoc_type_str, error);
2757 if (assoc != NULL) {
2758 free(assoc);
2761 if (error != 0) {
2762 dlist_free_items(*list, NULL);
2763 *list = NULL;
2766 return (error);
2770 * FUNCTION: disk_get_hbas(dm_descriptor_t disk, dlist_t **list)
2772 * INPUT: disk - a dm_descriptor_t handle for a disk
2774 * OUTPUT: list - a pointer to a dlist_t list to hold the
2775 * HBAs associated with the input disk
2777 * RETURNS: int - 0 on success
2778 * !0 otherwise.
2780 * PURPOSE: Helper which retrieves the known HBAs for a disk device.
2784 disk_get_hbas(
2785 dm_descriptor_t disk,
2786 dlist_t **list)
2788 return (disk_get_associated_desc(disk, DM_CONTROLLER,
2789 gettext("controller"), list));
2793 * FUNCTION: disk_get_paths(dm_descriptor_t disk, dlist_t **list)
2795 * INPUT: disk - a dm_descriptor_t handle for a disk
2797 * OUTPUT: list - a pointer to a dlist_t list to hold the
2798 * paths associated with the input disk
2800 * RETURNS: int - 0 on success
2801 * !0 otherwise.
2803 * PURPOSE: Helper which retrieves the known paths for a disk device.
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.
2810 disk_get_paths(
2811 dm_descriptor_t disk,
2812 dlist_t **list)
2814 return (disk_get_associated_desc(disk, DM_PATH,
2815 gettext("path"), list));
2819 * FUNCTION: disk_get_aliases(dm_descriptor_t disk, dlist_t **list)
2821 * INPUT: disk - a dm_descriptor_t handle for a disk
2823 * OUTPUT: list - a pointer to a dlist_t list to hold the
2824 * alias descriptors associated with the input disk
2826 * RETURNS: int - 0 on success
2827 * !0 otherwise.
2829 * PURPOSE: Helper which retrieves the known aliases for a disk device.
2831 * Aliases are the different CTD names for the disk drive when
2832 * MPXIO is not enabled for multipathed drives.
2835 disk_get_aliases(
2836 dm_descriptor_t disk,
2837 dlist_t **list)
2839 return (disk_get_associated_desc(disk, DM_ALIAS,
2840 gettext("alias"), list));
2844 * FUNCTION: compare_string_to_desc_name_or_alias(
2845 * void *str, void *desc)
2847 * INPUT: str - opaque pointer
2848 * descr - opaque pointer
2850 * RETURNS: int - <0 - if str < desc.name
2851 * 0 - if str == desc.name
2852 * >0 - if str > desc.name
2854 * PURPOSE: dlist_t helper which compares a string to the name
2855 * and aliases associated with the input dm_descriptor_t
2856 * handle.
2858 * Comparison is done via compare_device_names.
2860 static int
2861 compare_string_to_desc_name_or_alias(
2862 void *str,
2863 void *desc)
2865 char *dname = NULL;
2866 int result = -1;
2868 assert(str != (char *)NULL);
2869 assert(desc != (dm_descriptor_t)0);
2871 (void) get_display_name((uintptr_t)desc, &dname);
2873 /* try name first, then aliases */
2874 if ((result = compare_device_names(str, dname)) != 0) {
2875 dlist_t *aliases = NULL;
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;
2882 dlist_free_items(aliases, free);
2885 return (result);
2889 * FUNCTION: hba_get_by_name(char *name, dm_descriptor_t *hba)
2891 * INPUT: name - a char * disk name
2893 * OUTPUT: hba - a pointer to a dm_descriptor_t to hold the
2894 * HBA corresponding to the input name, if found
2896 * RETURNS: int - 0 on success
2897 * !0 otherwise
2899 * PURPOSE: Helper which iterates the known HBAs, searching for
2900 * the one matching name.
2902 * If no HBA matches the name, 0 is returned and the
2903 * value of 'hba' will be (dm_descriptor_t)0;
2906 hba_get_by_name(
2907 char *name,
2908 dm_descriptor_t *hba)
2910 int error = 0;
2911 dlist_t *list = NULL;
2912 dlist_t *item = NULL;
2914 *hba = (dm_descriptor_t)0;
2916 if (name == NULL) {
2917 return (0);
2920 if ((error = get_known_hbas(&list)) != 0) {
2921 return (error);
2924 if ((item = dlist_find(list, name,
2925 compare_string_to_desc_name_or_alias)) != NULL) {
2926 *hba = (uintptr_t)item->obj;
2929 return (error);
2933 * FUNCTION: disk_get_by_name(char *name, dm_descriptor_t *disk)
2935 * INPUT: name - a char * disk name
2937 * OUTPUT: disk - a pointer to a dm_descriptor_t to hold the
2938 * disk corresponding to the input name, if found
2940 * RETURNS: int - 0 on success
2941 * !0 otherwise.
2943 * PURPOSE: Helper which retrieves a dm_descriptor_t disk handle
2944 * by name.
2946 * If no disk is found for the input name, variations of
2947 * the name are tried.
2949 * If the input name is unqualified, an appropriate leading
2950 * path is prepended.
2952 * If the input name is qualified, the leading path is
2953 * removed.
2955 * If no disk is found for the variations, 0 is returned
2956 * and the value of 'disk' will be (dm_descriptor_t)0;
2959 disk_get_by_name(
2960 char *name,
2961 dm_descriptor_t *disk)
2963 assert(name != (char *)NULL);
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);
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);
2981 *disk = find_cached_descriptor(buf);
2986 * since the descriptor cache includes HBAs, disks and slices,
2987 * what gets returned may not be a disk... make sure it is
2989 if (*disk != (dm_descriptor_t)0) {
2990 if (dm_get_type(*disk) != DM_DRIVE) {
2991 *disk = (dm_descriptor_t)0;
2995 return (0);
2999 * FUNCTION: slice_get_by_name(char *name, dm_descriptor_t *slice)
3001 * INPUT: name - a char * slice name
3003 * OUTPUT: slice - a pointer to a dm_descriptor_t to hold the
3004 * slice corresponding to the input name, if found.
3006 * RETURNS: int - 0 on success
3007 * !0 otherwise.
3009 * PURPOSE: Helper which iterates the known slices, searching for
3010 * the one matching name.
3012 * If no slice is found for the input name, variations of
3013 * the name are tried.
3015 * If the input name is unqualified, an appropriate leading
3016 * path is prepended.
3018 * If the input name is qualified, the leading path is
3019 * removed.
3021 * If no slice matches the variations, 0 is returned and the
3022 * value of 'slice' will be (dm_descriptor_t)0;
3025 slice_get_by_name(
3026 char *name,
3027 dm_descriptor_t *slice)
3029 assert(name != (char *)NULL);
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);
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);
3048 *slice = find_cached_descriptor(buf);
3053 * since the descriptor cache includes HBAs, disks and slices,
3054 * what gets returned may not be a slice... make sure it is
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;
3063 return (0);
3067 * FUNCTION: extract_hbaname(char *name, char **hbaname)
3069 * INPUT: slicename - a char * device name
3071 * OUTPUT: hbaname - a pointer to a char * to hold the hbaname derived
3072 * from the input name.
3074 * RETURNS: int - 0 on success
3075 * !0 otherwise.
3077 * PURPOSE: Helper which extracts the HBA name from the input name.
3079 * If the input name is in ctd form, extracts just the cX part,
3080 * by truncating everything following the last 't'.
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'.
3086 * The returned string must be passed to free().
3089 extract_hbaname(
3090 char *name,
3091 char **hbaname)
3093 char *cp;
3095 if (is_ctd_name(name)) {
3096 if ((*hbaname = strdup(name)) == NULL) {
3097 return (ENOMEM);
3099 if ((cp = strrchr(*hbaname, 'd')) != NULL) {
3100 *cp = '\0';
3102 if ((cp = strrchr(*hbaname, 't')) != NULL) {
3103 *cp = '\0';
3107 return (0);
3111 * FUNCTION: extract_diskname(char *slicename, char **diskname)
3113 * INPUT: slicename - a char * slice name
3115 * OUTPUT: diskname - a pointer to a char * to hold the diskname derived
3116 * from the input slicename.
3118 * RETURNS: int - 0 on success
3119 * !0 otherwise.
3121 * PURPOSE: Helper which extracts the disk's name from a slice name.
3123 * Checks to see if the input slicename is in ctd or did form,
3124 * and if so, truncates everything following the last 's'.
3126 * If the input slicename is BSD-like, truncate the last
3127 * character (a-h).
3129 * The returned string must be passed to free().
3132 extract_diskname(
3133 char *slicename,
3134 char **diskname)
3136 char *cp;
3138 if (is_ctd_slice_name(slicename) || is_did_slice_name(slicename) ||
3139 is_ctd_like_slice_name(slicename)) {
3141 if ((*diskname = strdup(slicename)) == NULL) {
3142 return (ENOMEM);
3144 if ((cp = strrchr(*diskname, 's')) != NULL) {
3145 *cp = '\0';
3148 } else if (is_bsd_like_slice_name(slicename)) {
3150 if ((*diskname = strdup(slicename)) == NULL) {
3151 return (ENOMEM);
3153 (*diskname)[strlen((*diskname)-1)] = '\0';
3157 return (0);
3161 * FUNCTION: get_disk_for_named_slice(char *slicename,
3162 * dm_descriptor_t disk)
3164 * INPUT: slicename - a char * slice name
3166 * OUTPUT: disk - a pointer to a dm_descriptor_t to hold the
3167 * disk corresponding to the input name, if found
3169 * RETURNS: int - 0 on success
3170 * !0 otherwise.
3172 * PURPOSE: Helper which locates the disk dm_descriptor_t handle for
3173 * the input slice name.
3175 * If no disk matches the name, 0 is returned and the
3176 * value of 'disk' will be (dm_descriptor_t)0;
3179 get_disk_for_named_slice(
3180 char *slicename,
3181 dm_descriptor_t *disk)
3183 dm_descriptor_t slice = (dm_descriptor_t)0;
3184 int error = 0;
3186 assert(slicename != NULL);
3188 /* find disk for slice */
3189 if ((error = slice_get_by_name(slicename, &slice)) == 0) {
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;
3198 error = extract_diskname(slicename, &dname);
3199 if (error == 0) {
3200 error = disk_get_by_name(dname, disk);
3202 free(dname);
3206 assert(*disk != (dm_descriptor_t)0);
3208 return (error);
3212 * FUNCTION: disk_get_reserved_indexes(dm_descriptor_t disk,
3213 * uint16_t **array)
3215 * INPUT: disk - a dm_descriptor_t disk handle
3217 * RETURNS: int - 0 on success
3218 * !0 otherwise
3220 * PURPOSE: Retrieves the input disk's list of reserved slice indices.
3222 * The list of reserved indices is stored as an array in
3223 * the disk's nvpair attribute list.
3225 static int
3226 disk_get_reserved_indexes(
3227 dm_descriptor_t disk,
3228 uint16_t **array)
3230 nvlist_t *attrs = NULL;
3231 uint_t nelem = 0;
3232 int error = 0;
3234 if ((error = get_cached_attributes(disk, &attrs)) != 0) {
3235 return (error);
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;
3246 return (error);
3250 * FUNCTION: disk_reserve_index(dm_descriptor_t disk, uint16_t index)
3252 * INPUT: disk - a disk dm_descirptor_t handle
3253 * undex - a VTOC slice index
3255 * RETURNS: int - 0 on success
3256 * !0 otherwise
3258 * PURPOSE: Reserves the input VTOC slice index for the input disk.
3260 * The list of reserved indices is stored as an array in
3261 * the disk's nvpair attribute list.
3264 disk_reserve_index(
3265 dm_descriptor_t disk,
3266 uint16_t index)
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;
3275 if ((error = get_cached_attributes(disk, &attrs)) != 0) {
3276 return (error);
3279 if ((error = get_uint16_array(
3280 attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) {
3281 if (error != ENOENT) {
3282 return (error);
3284 /* no reserved indices yet */
3285 error = 0;
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];
3294 newindexes[(int)index] = 1;
3296 error = set_uint16_array(attrs, ATTR_RESERVED_INDEX,
3297 newindexes, VTOC_SIZE);
3299 free(newindexes);
3300 } else {
3301 error = ENOMEM;
3303 return (error);
3307 * FUNCTION: disk_release_index(dm_descriptor_t disk, uint16_t index)
3309 * INPUT: disk - a disk dm_descirptor_t handle
3310 * undex - a VTOC slice index
3312 * RETURNS: int - 0 on success
3313 * !0 otherwise
3315 * PURPOSE: Releases the input VTOC slice index for the input disk.
3316 * The index was previously reserved by disk_reserve_index()
3319 disk_release_index(
3320 dm_descriptor_t disk,
3321 uint16_t index)
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;
3330 if ((error = get_cached_attributes(disk, &attrs)) != 0) {
3331 return (error);
3334 if ((error = get_uint16_array(
3335 attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) {
3336 if (error != ENOENT) {
3337 return (error);
3339 error = 0;
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];
3348 /* release index */
3349 newindexes[(int)index] = 0;
3351 error = set_uint16_array(attrs, ATTR_RESERVED_INDEX,
3352 newindexes, VTOC_SIZE);
3354 free(newindexes);
3355 } else {
3356 error = ENOMEM;
3359 return (error);
3363 * FUNCTION: print_get_assoc_desc_error(dm_descriptor_t desc, char *which,
3364 * int error)
3366 * INPUT: desc - a dm_descriptor_t handle
3367 * which - a char * indicating which association
3368 * error - an integer error value
3370 * PURPOSE: Utility function to print an error message for a failed
3371 * call to dm_get_associated_descriptors().
3373 * Extracts the device's CTD name and formats an error message.
3375 void
3376 print_get_assoc_desc_error(
3377 dm_descriptor_t desc,
3378 char *which,
3379 int error)
3381 char *name = "";
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);
3389 volume_set_error(
3390 gettext("Unexpected error getting associated "
3391 "descriptors for '%s'"),
3392 name);
3396 * FUNCTION: print_get_desc_attr_error(dm_descriptor_t desc,
3397 * char *devtype, char *attr, int error)
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
3404 * PURPOSE: Shared utility function to print an error message for a failed
3405 * call to retrieve an attribute for a descriptor.
3407 * Extracts the device's CTD name and formats an error message.
3409 void
3410 print_get_desc_attr_error(
3411 dm_descriptor_t desc,
3412 char *devtype,
3413 char *attr,
3414 int error)
3416 char *name = "";
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);
3423 volume_set_error(
3424 gettext("Unexpected error getting attribute '%s.%s' for '%s'"),
3425 devtype, attr, name);
3429 * FUNCTION: print_set_desc_attr_error(dm_descriptor_t desc,
3430 * char *devtype, char *attr, int error)
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
3437 * PURPOSE: Shared utility function to print an error message for a failed
3438 * call to set an attribute for a descriptor.
3440 * Extracts the device's CTD name and formats an error message.
3442 void
3443 print_set_desc_attr_error(
3444 dm_descriptor_t desc,
3445 char *devtype,
3446 char *attr,
3447 int error)
3449 char *name = "";
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);
3456 volume_set_error(
3457 gettext("Unexpected error setting attribute '%s.%s' for '%s'"),
3458 devtype, attr, name);