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