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 #include <libdevinfo.h>
35 #include <sys/sunddi.h>
36 #include <sys/types.h>
41 #include <sys/dktp/fdisk.h>
42 #include <sys/efi_partition.h>
44 #include "libdiskmgt.h"
45 #include "disks_private.h"
46 #include "partition.h"
48 #define VT_ENOTSUP (-5)
55 typedef int (*detectorp
)(char *, nvlist_t
*, int *);
57 static detectorp detectors
[] = {
64 inuse_fs
, /* fs should always be last */
68 static int add_inuse(char *name
, nvlist_t
*attrs
);
69 static int desc_ok(descriptor_t
*dp
);
70 static void dsk2rdsk(char *dsk
, char *rdsk
, int size
);
71 static int get_attrs(descriptor_t
*dp
, int fd
, nvlist_t
*attrs
);
72 static descriptor_t
**get_fixed_assocs(descriptor_t
*desc
, int *errp
);
73 static int get_slice_num(slice_t
*devp
);
74 static int match_fixed_name(disk_t
*dp
, char *name
, int *errp
);
75 static int make_fixed_descriptors(disk_t
*dp
);
78 slice_get_assoc_descriptors(descriptor_t
*desc
, dm_desc_type_t type
,
88 return (media_get_assocs(desc
, errp
));
90 return (partition_get_assocs(desc
, errp
));
98 * This is called by media/partition to get the slice descriptors for the given
99 * media/partition descriptor.
100 * For media, just get the slices, but for a partition, it must be a solaris
101 * partition and if there are active partitions, it must be the active one.
104 slice_get_assocs(descriptor_t
*desc
, int *errp
)
106 /* Just check the first drive name. */
107 if (desc
->p
.disk
->aliases
== NULL
) {
109 return (libdiskmgt_empty_desc_array(errp
));
112 return (get_fixed_assocs(desc
, errp
));
116 slice_get_attributes(descriptor_t
*dp
, int *errp
)
118 nvlist_t
*attrs
= NULL
;
120 char devpath
[MAXPATHLEN
];
127 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
132 /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
133 dsk2rdsk(dp
->name
, devpath
, sizeof (devpath
));
134 fd
= open(devpath
, O_RDONLY
|O_NDELAY
);
136 if ((*errp
= get_attrs(dp
, fd
, attrs
)) != 0) {
149 * Look for the slice by the slice devpath.
152 slice_get_descriptor_by_name(char *name
, int *errp
)
157 for (dp
= cache_get_disklist(); dp
!= NULL
; dp
= dp
->next
) {
158 found
= match_fixed_name(dp
, name
, errp
);
161 char mname
[MAXPATHLEN
];
168 (void) media_read_name(dp
, mname
, sizeof (mname
));
170 return (cache_get_desc(DM_SLICE
, dp
, name
, mname
,
181 slice_get_descriptors(int filter
[], int *errp
)
183 return (cache_get_descriptors(DM_SLICE
, errp
));
187 slice_get_name(descriptor_t
*desc
)
193 slice_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
198 if (stat_type
!= DM_SLICE_STAT_USE
) {
205 if (nvlist_alloc(&stats
, NVATTRS_STAT
, 0) != 0) {
210 if ((*errp
= add_inuse(dp
->name
, stats
)) != 0) {
214 /* if no cluster use, check for a use of the local name */
215 if (nvlist_lookup_string(stats
, DM_USED_BY
, &str
) != 0) {
219 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->cluster
) {
222 struct dk_minfo minfo
;
223 struct dk_cinfo dkinfo
;
224 char devpath
[MAXPATHLEN
];
227 /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
228 dsk2rdsk(dp
->name
, devpath
, sizeof (devpath
));
229 fd
= open(devpath
, O_RDONLY
|O_NDELAY
);
231 if (fd
>= 0 && media_read_info(fd
, &minfo
) &&
232 ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
233 snum
= dkinfo
.dki_partition
;
241 for (sp
= diskp
->aliases
->orig_paths
; sp
!= NULL
;
244 if (sp
->slice_num
== snum
) {
245 char localpath
[MAXPATHLEN
];
247 slice_rdsk2dsk(sp
->devpath
, localpath
,
250 if ((*errp
= add_inuse(localpath
, stats
)) != 0) {
265 * A slice descriptor points to a disk, the name is the devpath and the
266 * secondary name is the media name.
269 slice_make_descriptors()
273 dp
= cache_get_disklist();
277 error
= make_fixed_descriptors(dp
);
288 /* convert rdsk paths to dsk paths */
290 slice_rdsk2dsk(char *rdsk
, char *dsk
, int size
)
294 (void) strlcpy(dsk
, rdsk
, size
);
296 if ((strp
= strstr(dsk
, "/rdsk/")) == NULL
) {
297 /* not rdsk, check for floppy */
298 strp
= strstr(dsk
, "/rdiskette");
302 strp
++; /* move ptr to the r in rdsk or rdiskette */
304 /* move the succeeding chars over by one */
313 * Check if/how the slice is used.
316 add_inuse(char *name
, nvlist_t
*attrs
)
321 for (i
= 0; detectors
[i
] != NULL
; i
++) {
322 if (detectors
[i
](name
, attrs
, &error
) || error
!= 0) {
333 /* return 1 if the slice descriptor is still valid, 0 if not. */
335 desc_ok(descriptor_t
*dp
)
337 /* First verify the media name for removable media */
338 if (dp
->p
.disk
->removable
) {
339 char mname
[MAXPATHLEN
];
341 if (!media_read_name(dp
->p
.disk
, mname
, sizeof (mname
))) {
346 return (libdiskmgt_str_eq(dp
->secondary_name
, NULL
));
348 return (libdiskmgt_str_eq(dp
->secondary_name
, mname
));
353 * We could verify the slice is still there, but other code down the
354 * line already does these checks (e.g. see get_attrs).
360 /* convert dsk paths to rdsk paths */
362 dsk2rdsk(char *dsk
, char *rdsk
, int size
)
367 (void) strlcpy(rdsk
, dsk
, size
);
369 /* make sure there is enough room to add the r to dsk */
371 if (len
+ 2 > size
) {
375 if ((slashp
= strstr(rdsk
, "/dsk/")) == NULL
) {
376 /* not dsk, check for floppy */
377 slashp
= strstr(rdsk
, "/diskette");
380 if (slashp
!= NULL
) {
383 endp
= rdsk
+ len
; /* point to terminating 0 */
384 /* move the succeeding chars over by one */
388 } while (endp
!= slashp
);
395 get_attrs(descriptor_t
*dp
, int fd
, nvlist_t
*attrs
)
397 struct dk_minfo minfo
;
399 int data_format
= FMT_UNKNOWN
;
404 struct dk_cinfo dkinfo
;
406 char localpath
[MAXPATHLEN
];
415 /* First make sure media is inserted and spun up. */
416 if (!media_read_info(fd
, &minfo
)) {
420 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
421 data_format
= FMT_VTOC
;
422 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
423 data_format
= FMT_EFI
;
424 if (nvlist_add_boolean(attrs
, DM_EFI
) != 0) {
430 if (data_format
== FMT_UNKNOWN
) {
434 if (ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
435 snum
= dkinfo
.dki_partition
;
438 /* check the slice */
439 if (data_format
== FMT_VTOC
) {
440 if (snum
< 0 || snum
>= vtoc
.v_nparts
||
441 vtoc
.v_part
[snum
].p_size
== 0) {
444 } else { /* data_format == FMT_EFI */
445 if (snum
< 0 || snum
>= efip
->efi_nparts
||
446 efip
->efi_parts
[snum
].p_size
== 0) {
452 /* the slice exists */
454 if (nvlist_add_uint32(attrs
, DM_INDEX
, snum
) != 0) {
455 if (data_format
== FMT_EFI
) {
461 if (data_format
== FMT_VTOC
) {
462 if (nvlist_add_uint64(attrs
, DM_START
, vtoc
.v_part
[snum
].p_start
)
467 if (nvlist_add_uint64(attrs
, DM_SIZE
, vtoc
.v_part
[snum
].p_size
)
472 if (nvlist_add_uint32(attrs
, DM_TAG
, vtoc
.v_part
[snum
].p_tag
)
477 if (nvlist_add_uint32(attrs
, DM_FLAG
, vtoc
.v_part
[snum
].p_flag
)
482 } else { /* data_format == FMT_EFI */
483 if (nvlist_add_uint64(attrs
, DM_START
,
484 efip
->efi_parts
[snum
].p_start
) != 0) {
489 if (nvlist_add_uint64(attrs
, DM_SIZE
, efip
->efi_parts
[snum
].p_size
)
495 if (efip
->efi_parts
[snum
].p_name
[0] != 0) {
496 char label
[EFI_PART_NAME_LEN
+ 1];
498 (void) snprintf(label
, sizeof (label
), "%.*s",
499 EFI_PART_NAME_LEN
, efip
->efi_parts
[snum
].p_name
);
500 if (nvlist_add_string(attrs
, DM_EFI_NAME
, label
) != 0) {
507 if (data_format
== FMT_EFI
) {
511 if (inuse_mnt(dp
->name
, attrs
, &error
)) {
519 * Some extra attrs for cluster slices.
521 * get localname and possible mnt point for localpath
525 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->cluster
) {
528 for (sp
= diskp
->aliases
->orig_paths
; sp
!= NULL
; sp
= sp
->next
) {
529 if (sp
->slice_num
== -1) {
530 /* determine the slice number for this path */
532 struct dk_cinfo dkinfo
;
534 if ((sfd
= open(sp
->devpath
, O_RDONLY
|O_NDELAY
)) >= 0) {
535 if (ioctl(sfd
, DKIOCINFO
, &dkinfo
) >= 0) {
536 sp
->slice_num
= dkinfo
.dki_partition
;
542 if (sp
->slice_num
== snum
) {
543 slice_rdsk2dsk(sp
->devpath
, localpath
, sizeof (localpath
));
545 if (nvlist_add_string(attrs
, DM_LOCALNAME
, localpath
)
551 if (inuse_mnt(localpath
, attrs
, &error
)) {
563 if (fstat(fd
, &buf
) != -1) {
564 if (nvlist_add_uint64(attrs
, DM_DEVT
, buf
.st_rdev
) != 0) {
570 * We need to open the cooked slice (not the raw one) to get the
571 * correct devid. Also see if we need to read the localpath for the
572 * cluster disk, since the minor name is unavailable for the did pseudo
575 if (localpath
[0] != 0) {
576 cooked_fd
= open(localpath
, O_RDONLY
|O_NDELAY
);
578 cooked_fd
= open(dp
->name
, O_RDONLY
|O_NDELAY
);
581 if (cooked_fd
>= 0) {
585 if (devid_get(cooked_fd
, &devid
) == 0) {
588 if (devid_get_minor_name(cooked_fd
, &minor
) == 0) {
591 if ((devidstr
= devid_str_encode(devid
, minor
)) != 0) {
593 if (nvlist_add_string(attrs
, DM_DEVICEID
, devidstr
)
598 devid_str_free(devidstr
);
600 devid_str_free(minor
);
604 (void) close(cooked_fd
);
614 static descriptor_t
**
615 get_fixed_assocs(descriptor_t
*desc
, int *errp
)
619 int data_format
= FMT_UNKNOWN
;
624 char *media_name
= NULL
;
626 descriptor_t
**slices
;
628 if ((fd
= drive_open_disk(desc
->p
.disk
, NULL
, 0)) < 0) {
633 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
634 data_format
= FMT_VTOC
;
635 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
636 data_format
= FMT_EFI
;
640 return (libdiskmgt_empty_desc_array(errp
));
644 /* count the number of slices */
645 for (cnt
= 0, devp
= desc
->p
.disk
->aliases
->devpaths
; devp
!= NULL
;
646 devp
= devp
->next
, cnt
++);
648 /* allocate the array for the descriptors */
649 slices
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
650 if (slices
== NULL
) {
651 if (data_format
== FMT_EFI
) {
658 /* get the media name from the descriptor */
659 if (desc
->type
== DM_MEDIA
) {
660 media_name
= desc
->name
;
662 /* must be a DM_PARTITION */
663 media_name
= desc
->secondary_name
;
667 for (devp
= desc
->p
.disk
->aliases
->devpaths
; devp
!= NULL
;
671 char devpath
[MAXPATHLEN
];
673 slice_num
= get_slice_num(devp
);
674 /* can't get slicenum, so no need to keep trying the drive */
675 if (slice_num
== -1) {
679 if (data_format
== FMT_VTOC
) {
680 if (slice_num
>= vtoc
.v_nparts
||
681 vtoc
.v_part
[slice_num
].p_size
== 0) {
684 } else { /* data_format == FMT_EFI */
685 if (slice_num
>= efip
->efi_nparts
||
686 efip
->efi_parts
[slice_num
].p_size
== 0) {
691 slice_rdsk2dsk(devp
->devpath
, devpath
, sizeof (devpath
));
692 slices
[pos
] = cache_get_desc(DM_SLICE
, desc
->p
.disk
, devpath
,
695 cache_free_descriptors(slices
);
696 if (data_format
== FMT_EFI
) {
705 if (data_format
== FMT_EFI
) {
714 get_slice_num(slice_t
*devp
)
716 /* check if we already determined the devpath slice number */
717 if (devp
->slice_num
== -1) {
720 if ((fd
= open(devp
->devpath
, O_RDONLY
|O_NDELAY
)) >= 0) {
721 struct dk_cinfo dkinfo
;
722 if (ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
723 devp
->slice_num
= dkinfo
.dki_partition
;
729 return (devp
->slice_num
);
733 make_fixed_descriptors(disk_t
*dp
)
738 char mname
[MAXPATHLEN
];
739 int data_format
= FMT_UNKNOWN
;
743 /* Just check the first drive name. */
744 if ((ap
= dp
->aliases
) == NULL
) {
749 (void) media_read_name(dp
, mname
, sizeof (mname
));
751 for (devp
= ap
->devpaths
; devp
!= NULL
; devp
= devp
->next
) {
753 char devpath
[MAXPATHLEN
];
755 slice_num
= get_slice_num(devp
);
756 /* can't get slicenum, so no need to keep trying the drive */
757 if (slice_num
== -1) {
761 if (data_format
== FMT_UNKNOWN
) {
765 if ((fd
= drive_open_disk(dp
, NULL
, 0)) >= 0) {
766 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
767 data_format
= FMT_VTOC
;
768 } else if (status
== VT_ENOTSUP
&&
769 efi_alloc_and_read(fd
, &efip
) >= 0) {
770 data_format
= FMT_EFI
;
776 /* can't get slice data, so no need to keep trying the drive */
777 if (data_format
== FMT_UNKNOWN
) {
781 if (data_format
== FMT_VTOC
) {
782 if (slice_num
>= vtoc
.v_nparts
||
783 vtoc
.v_part
[slice_num
].p_size
== 0) {
786 } else { /* data_format == FMT_EFI */
787 if (slice_num
>= efip
->efi_nparts
||
788 efip
->efi_parts
[slice_num
].p_size
== 0) {
793 slice_rdsk2dsk(devp
->devpath
, devpath
, sizeof (devpath
));
794 cache_load_desc(DM_SLICE
, dp
, devpath
, mname
, &error
);
800 if (data_format
== FMT_EFI
) {
808 * Just look for the name on the devpaths we have cached. Return 1 if we
809 * find the name and the size of that slice is non-zero.
812 match_fixed_name(disk_t
*diskp
, char *name
, int *errp
)
819 int data_format
= FMT_UNKNOWN
;
828 while (devp
!= NULL
) {
829 char path
[MAXPATHLEN
];
831 slice_rdsk2dsk(devp
->devpath
, path
, sizeof (path
));
832 if (libdiskmgt_str_eq(path
, name
)) {
854 * If we found a match on the name we now have to check that this
855 * slice really exists (non-0 size).
858 slice_num
= get_slice_num(dp
);
859 /* can't get slicenum, so no slice */
860 if (slice_num
== -1) {
865 if ((fd
= drive_open_disk(diskp
, NULL
, 0)) < 0) {
870 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
871 data_format
= FMT_VTOC
;
872 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
873 data_format
= FMT_EFI
;
881 if (data_format
== FMT_VTOC
) {
882 if (slice_num
< vtoc
.v_nparts
&&
883 vtoc
.v_part
[slice_num
].p_size
> 0) {
887 } else { /* data_format == FMT_EFI */
888 if (slice_num
< efip
->efi_nparts
&&
889 efip
->efi_parts
[slice_num
].p_size
> 0) {