4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2017 Nexenta Systems, Inc.
32 #include <libdevinfo.h>
39 #include <sys/sunddi.h>
40 #include <sys/types.h>
45 #include <sys/dktp/fdisk.h>
46 #include <sys/efi_partition.h>
48 #include "libdiskmgt.h"
49 #include "disks_private.h"
50 #include "partition.h"
52 #define VT_ENOTSUP (-5)
59 typedef int (*detectorp
)(char *, nvlist_t
*, int *);
61 static detectorp detectors
[] = {
68 inuse_fs
, /* fs should always be last */
72 static int add_inuse(char *name
, nvlist_t
*attrs
);
73 static int desc_ok(descriptor_t
*dp
);
74 static void dsk2rdsk(char *dsk
, char *rdsk
, int size
);
75 static int get_attrs(descriptor_t
*dp
, int fd
, nvlist_t
*attrs
);
76 static descriptor_t
**get_fixed_assocs(descriptor_t
*desc
, int *errp
);
77 static int get_slice_num(slice_t
*devp
);
78 static int match_fixed_name(disk_t
*dp
, char *name
, int *errp
);
79 static int make_fixed_descriptors(disk_t
*dp
);
82 slice_get_assoc_descriptors(descriptor_t
*desc
, dm_desc_type_t type
,
92 return (media_get_assocs(desc
, errp
));
94 return (partition_get_assocs(desc
, errp
));
102 * This is called by media/partition to get the slice descriptors for the given
103 * media/partition descriptor.
104 * For media, just get the slices, but for a partition, it must be a solaris
105 * partition and if there are active partitions, it must be the active one.
108 slice_get_assocs(descriptor_t
*desc
, int *errp
)
110 /* Just check the first drive name. */
111 if (desc
->p
.disk
->aliases
== NULL
) {
113 return (libdiskmgt_empty_desc_array(errp
));
116 return (get_fixed_assocs(desc
, errp
));
120 slice_get_attributes(descriptor_t
*dp
, int *errp
)
122 nvlist_t
*attrs
= NULL
;
124 char devpath
[MAXPATHLEN
];
131 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
136 /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
137 dsk2rdsk(dp
->name
, devpath
, sizeof (devpath
));
138 fd
= open(devpath
, O_RDONLY
|O_NDELAY
);
140 if ((*errp
= get_attrs(dp
, fd
, attrs
)) != 0) {
153 * Look for the slice by the slice devpath.
156 slice_get_descriptor_by_name(char *name
, int *errp
)
161 for (dp
= cache_get_disklist(); dp
!= NULL
; dp
= dp
->next
) {
162 found
= match_fixed_name(dp
, name
, errp
);
165 char mname
[MAXPATHLEN
];
172 (void) media_read_name(dp
, mname
, sizeof (mname
));
174 return (cache_get_desc(DM_SLICE
, dp
, name
, mname
,
185 slice_get_descriptors(int filter
[], int *errp
)
187 return (cache_get_descriptors(DM_SLICE
, errp
));
191 slice_get_name(descriptor_t
*desc
)
197 slice_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
202 if (stat_type
!= DM_SLICE_STAT_USE
) {
209 if (nvlist_alloc(&stats
, NVATTRS_STAT
, 0) != 0) {
214 if ((*errp
= add_inuse(dp
->name
, stats
)) != 0) {
219 /* if no cluster use, check for a use of the local name */
220 if (nvlist_lookup_string(stats
, DM_USED_BY
, &str
) != 0) {
224 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->cluster
) {
227 struct dk_minfo minfo
;
228 struct dk_cinfo dkinfo
;
229 char devpath
[MAXPATHLEN
];
233 * dp->name is /dev/dsk, need to convert back to
236 dsk2rdsk(dp
->name
, devpath
, sizeof (devpath
));
237 fd
= open(devpath
, O_RDONLY
|O_NDELAY
);
239 if (fd
>= 0 && media_read_info(fd
, &minfo
) &&
240 ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
241 snum
= dkinfo
.dki_partition
;
249 for (sp
= diskp
->aliases
->orig_paths
;
250 sp
!= NULL
; sp
= sp
->next
) {
252 if (sp
->slice_num
== snum
) {
253 char localpath
[MAXPATHLEN
];
255 slice_rdsk2dsk(sp
->devpath
,
259 *errp
= add_inuse(localpath
,
277 * A slice descriptor points to a disk, the name is the devpath and the
278 * secondary name is the media name.
281 slice_make_descriptors()
285 dp
= cache_get_disklist();
289 error
= make_fixed_descriptors(dp
);
300 /* convert rdsk paths to dsk paths */
302 slice_rdsk2dsk(char *rdsk
, char *dsk
, int size
)
306 (void) strlcpy(dsk
, rdsk
, size
);
308 if ((strp
= strstr(dsk
, "/rdsk/")) == NULL
) {
309 /* not rdsk, check for floppy */
310 strp
= strstr(dsk
, "/rdiskette");
314 strp
++; /* move ptr to the r in rdsk or rdiskette */
316 /* move the succeeding chars over by one */
325 * Check if/how the slice is used.
328 add_inuse(char *name
, nvlist_t
*attrs
)
333 for (i
= 0; detectors
[i
] != NULL
; i
++) {
334 if (detectors
[i
](name
, attrs
, &error
) || error
!= 0) {
345 /* return 1 if the slice descriptor is still valid, 0 if not. */
347 desc_ok(descriptor_t
*dp
)
349 /* First verify the media name for removable media */
350 if (dp
->p
.disk
->removable
) {
351 char mname
[MAXPATHLEN
];
353 if (!media_read_name(dp
->p
.disk
, mname
, sizeof (mname
))) {
358 return (libdiskmgt_str_eq(dp
->secondary_name
, NULL
));
360 return (libdiskmgt_str_eq(dp
->secondary_name
, mname
));
365 * We could verify the slice is still there, but other code down the
366 * line already does these checks (e.g. see get_attrs).
372 /* convert dsk paths to rdsk paths */
374 dsk2rdsk(char *dsk
, char *rdsk
, int size
)
379 (void) strlcpy(rdsk
, dsk
, size
);
381 /* make sure there is enough room to add the r to dsk */
383 if (len
+ 2 > size
) {
387 if ((slashp
= strstr(rdsk
, "/dsk/")) == NULL
) {
388 /* not dsk, check for floppy */
389 slashp
= strstr(rdsk
, "/diskette");
392 if (slashp
!= NULL
) {
395 endp
= rdsk
+ len
; /* point to terminating 0 */
396 /* move the succeeding chars over by one */
400 } while (endp
!= slashp
);
407 get_attrs(descriptor_t
*dp
, int fd
, nvlist_t
*attrs
)
409 struct dk_minfo minfo
;
411 int data_format
= FMT_UNKNOWN
;
416 struct dk_cinfo dkinfo
;
418 char localpath
[MAXPATHLEN
];
427 /* First make sure media is inserted and spun up. */
428 if (!media_read_info(fd
, &minfo
)) {
432 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
433 data_format
= FMT_VTOC
;
434 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
435 data_format
= FMT_EFI
;
436 if (nvlist_add_boolean(attrs
, DM_EFI
) != 0) {
442 if (data_format
== FMT_UNKNOWN
) {
446 if (ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
447 snum
= dkinfo
.dki_partition
;
450 /* check the slice */
451 if (data_format
== FMT_VTOC
) {
452 if (snum
< 0 || snum
>= vtoc
.v_nparts
||
453 vtoc
.v_part
[snum
].p_size
== 0) {
456 } else { /* data_format == FMT_EFI */
457 if (snum
< 0 || snum
>= efip
->efi_nparts
||
458 efip
->efi_parts
[snum
].p_size
== 0) {
464 /* the slice exists */
466 if (nvlist_add_uint32(attrs
, DM_INDEX
, snum
) != 0) {
467 if (data_format
== FMT_EFI
) {
473 if (data_format
== FMT_VTOC
) {
474 if (nvlist_add_uint64(attrs
, DM_START
,
475 vtoc
.v_part
[snum
].p_start
) != 0) {
479 if (nvlist_add_uint64(attrs
, DM_SIZE
, vtoc
.v_part
[snum
].p_size
)
484 if (nvlist_add_uint32(attrs
, DM_TAG
, vtoc
.v_part
[snum
].p_tag
)
489 if (nvlist_add_uint32(attrs
, DM_FLAG
, vtoc
.v_part
[snum
].p_flag
)
494 } else { /* data_format == FMT_EFI */
495 if (nvlist_add_uint64(attrs
, DM_START
,
496 efip
->efi_parts
[snum
].p_start
) != 0) {
501 if (nvlist_add_uint64(attrs
, DM_SIZE
,
502 efip
->efi_parts
[snum
].p_size
) != 0) {
507 if (efip
->efi_parts
[snum
].p_name
[0] != 0) {
508 char label
[EFI_PART_NAME_LEN
+ 1];
510 (void) snprintf(label
, sizeof (label
), "%.*s",
511 EFI_PART_NAME_LEN
, efip
->efi_parts
[snum
].p_name
);
512 if (nvlist_add_string(attrs
, DM_EFI_NAME
, label
) != 0) {
519 if (data_format
== FMT_EFI
) {
523 if (inuse_mnt(dp
->name
, attrs
, &error
)) {
531 * Some extra attrs for cluster slices.
533 * get localname and possible mnt point for localpath
537 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->cluster
) {
540 for (sp
= diskp
->aliases
->orig_paths
; sp
!= NULL
;
542 if (sp
->slice_num
== -1) {
543 /* determine the slice number for this path */
545 struct dk_cinfo dkinfo
;
547 sfd
= open(sp
->devpath
, O_RDONLY
|O_NDELAY
);
549 if (ioctl(sfd
, DKIOCINFO
, &dkinfo
)
552 dkinfo
.dki_partition
;
558 if (sp
->slice_num
== snum
) {
559 slice_rdsk2dsk(sp
->devpath
, localpath
,
562 if (nvlist_add_string(attrs
, DM_LOCALNAME
,
568 if (inuse_mnt(localpath
, attrs
,
581 if (fstat(fd
, &buf
) != -1) {
582 if (nvlist_add_uint64(attrs
, DM_DEVT
, buf
.st_rdev
) != 0) {
588 * We need to open the cooked slice (not the raw one) to get the
589 * correct devid. Also see if we need to read the localpath for the
590 * cluster disk, since the minor name is unavailable for the did pseudo
593 if (localpath
[0] != 0) {
594 cooked_fd
= open(localpath
, O_RDONLY
|O_NDELAY
);
596 cooked_fd
= open(dp
->name
, O_RDONLY
|O_NDELAY
);
599 if (cooked_fd
>= 0) {
603 if (devid_get(cooked_fd
, &devid
) == 0) {
606 if (devid_get_minor_name(cooked_fd
, &minor
) == 0) {
609 devidstr
= devid_str_encode(devid
, minor
);
610 if (devidstr
!= NULL
) {
612 if (nvlist_add_string(attrs
,
613 DM_DEVICEID
, devidstr
) != 0) {
617 devid_str_free(devidstr
);
619 devid_str_free(minor
);
623 (void) close(cooked_fd
);
633 static descriptor_t
**
634 get_fixed_assocs(descriptor_t
*desc
, int *errp
)
638 int data_format
= FMT_UNKNOWN
;
643 char *media_name
= NULL
;
645 descriptor_t
**slices
;
647 if ((fd
= drive_open_disk(desc
->p
.disk
, NULL
, 0)) < 0) {
652 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
653 data_format
= FMT_VTOC
;
654 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
655 data_format
= FMT_EFI
;
659 return (libdiskmgt_empty_desc_array(errp
));
663 /* count the number of slices */
664 devp
= desc
->p
.disk
->aliases
->devpaths
;
665 for (cnt
= 0; devp
!= NULL
; devp
= devp
->next
)
668 /* allocate the array for the descriptors */
669 slices
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
670 if (slices
== NULL
) {
671 if (data_format
== FMT_EFI
) {
678 /* get the media name from the descriptor */
679 if (desc
->type
== DM_MEDIA
) {
680 media_name
= desc
->name
;
682 /* must be a DM_PARTITION */
683 media_name
= desc
->secondary_name
;
687 for (devp
= desc
->p
.disk
->aliases
->devpaths
; devp
!= NULL
;
691 char devpath
[MAXPATHLEN
];
693 slice_num
= get_slice_num(devp
);
694 /* can't get slicenum, so no need to keep trying the drive */
695 if (slice_num
== -1) {
699 if (data_format
== FMT_VTOC
) {
700 if (slice_num
>= vtoc
.v_nparts
||
701 vtoc
.v_part
[slice_num
].p_size
== 0) {
704 } else { /* data_format == FMT_EFI */
705 if (slice_num
>= efip
->efi_nparts
||
706 efip
->efi_parts
[slice_num
].p_size
== 0) {
711 slice_rdsk2dsk(devp
->devpath
, devpath
, sizeof (devpath
));
712 slices
[pos
] = cache_get_desc(DM_SLICE
, desc
->p
.disk
, devpath
,
715 cache_free_descriptors(slices
);
716 if (data_format
== FMT_EFI
) {
725 if (data_format
== FMT_EFI
) {
734 get_slice_num(slice_t
*devp
)
736 /* check if we already determined the devpath slice number */
737 if (devp
->slice_num
== -1) {
740 if ((fd
= open(devp
->devpath
, O_RDONLY
|O_NDELAY
)) >= 0) {
741 struct dk_cinfo dkinfo
;
742 if (ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
743 devp
->slice_num
= dkinfo
.dki_partition
;
749 return (devp
->slice_num
);
753 make_fixed_descriptors(disk_t
*dp
)
758 char mname
[MAXPATHLEN
];
759 int data_format
= FMT_UNKNOWN
;
763 /* Just check the first drive name. */
764 if ((ap
= dp
->aliases
) == NULL
) {
769 (void) media_read_name(dp
, mname
, sizeof (mname
));
771 for (devp
= ap
->devpaths
; devp
!= NULL
; devp
= devp
->next
) {
773 char devpath
[MAXPATHLEN
];
775 slice_num
= get_slice_num(devp
);
776 /* can't get slicenum, so no need to keep trying the drive */
777 if (slice_num
== -1) {
781 if (data_format
== FMT_UNKNOWN
) {
785 if ((fd
= drive_open_disk(dp
, NULL
, 0)) >= 0) {
786 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
787 data_format
= FMT_VTOC
;
788 } else if (status
== VT_ENOTSUP
&&
789 efi_alloc_and_read(fd
, &efip
) >= 0) {
790 data_format
= FMT_EFI
;
796 /* can't get slice data, so no need to keep trying the drive */
797 if (data_format
== FMT_UNKNOWN
) {
801 if (data_format
== FMT_VTOC
) {
802 if (slice_num
>= vtoc
.v_nparts
||
803 vtoc
.v_part
[slice_num
].p_size
== 0) {
806 } else { /* data_format == FMT_EFI */
807 if (slice_num
>= efip
->efi_nparts
||
808 efip
->efi_parts
[slice_num
].p_size
== 0) {
813 slice_rdsk2dsk(devp
->devpath
, devpath
, sizeof (devpath
));
814 cache_load_desc(DM_SLICE
, dp
, devpath
, mname
, &error
);
820 if (data_format
== FMT_EFI
) {
828 * Just look for the name on the devpaths we have cached. Return 1 if we
829 * find the name and the size of that slice is non-zero.
832 match_fixed_name(disk_t
*diskp
, char *name
, int *errp
)
839 int data_format
= FMT_UNKNOWN
;
848 while (devp
!= NULL
) {
849 char path
[MAXPATHLEN
];
851 slice_rdsk2dsk(devp
->devpath
, path
, sizeof (path
));
852 if (libdiskmgt_str_eq(path
, name
)) {
874 * If we found a match on the name we now have to check that this
875 * slice really exists (non-0 size).
878 slice_num
= get_slice_num(dp
);
879 /* can't get slicenum, so no slice */
880 if (slice_num
== -1) {
885 if ((fd
= drive_open_disk(diskp
, NULL
, 0)) < 0) {
890 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
891 data_format
= FMT_VTOC
;
892 } else if (status
== VT_ENOTSUP
) {
893 status
= efi_alloc_and_read(fd
, &efip
);
895 data_format
= FMT_EFI
;
896 } else if (status
== VT_ERROR
&& errno
== ENOTTY
) {
907 if (data_format
== FMT_VTOC
) {
908 if (slice_num
< vtoc
.v_nparts
&&
909 vtoc
.v_part
[slice_num
].p_size
> 0) {
913 } else { /* data_format == FMT_EFI */
914 if (slice_num
< efip
->efi_nparts
&&
915 efip
->efi_parts
[slice_num
].p_size
> 0) {