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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <libdevinfo.h>
34 #include <sys/sunddi.h>
35 #include <sys/types.h>
38 #include <sys/efi_partition.h>
40 #include "libdiskmgt.h"
41 #include "disks_private.h"
42 #include "partition.h"
44 #define IOCTLRETRIES 2
45 #define IOCTLRETRYINTERVAL 1
47 static descriptor_t
**apply_filter(descriptor_t
**media
, int filter
[],
49 static int get_attrs(disk_t
*dp
, int fd
, nvlist_t
*attrs
);
50 static int get_rmm_name(disk_t
*dp
, char *mname
, int size
);
51 static int get_media_type(uint_t media_type
);
52 static int desc_ok(descriptor_t
*dp
);
55 * This function gets the descriptors we are associated with.
58 media_get_assoc_descriptors(descriptor_t
*desc
, dm_desc_type_t type
,
68 return (drive_get_assocs(desc
, errp
));
70 return (partition_get_assocs(desc
, errp
));
72 return (slice_get_assocs(desc
, errp
));
80 * Get the media descriptors for the given drive/partition/slice.
83 media_get_assocs(descriptor_t
*dp
, int *errp
)
86 char mname
[MAXPATHLEN
];
88 if (!media_read_name(dp
->p
.disk
, mname
, sizeof (mname
))) {
90 * For drives, this means no media but slice/part.
93 if (dp
->type
== DM_DRIVE
) {
94 return (libdiskmgt_empty_desc_array(errp
));
101 /* make the snapshot */
102 media
= (descriptor_t
**)calloc(2, sizeof (descriptor_t
*));
108 media
[0] = cache_get_desc(DM_MEDIA
, dp
->p
.disk
, mname
, NULL
, errp
);
120 media_get_attributes(descriptor_t
*dp
, int *errp
)
122 nvlist_t
*attrs
= NULL
;
130 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
135 fd
= drive_open_disk(dp
->p
.disk
, NULL
, 0);
137 if ((*errp
= get_attrs(dp
->p
.disk
, fd
, attrs
)) != 0) {
150 media_get_descriptor_by_name(char *name
, int *errp
)
152 descriptor_t
**media
;
154 descriptor_t
*medium
= NULL
;
156 media
= cache_get_descriptors(DM_MEDIA
, errp
);
161 for (i
= 0; media
[i
]; i
++) {
162 if (libdiskmgt_str_eq(name
, media
[i
]->name
)) {
165 /* clean up the unused descriptors */
166 cache_free_descriptor(media
[i
]);
171 if (medium
== NULL
) {
179 media_get_descriptors(int filter
[], int *errp
)
181 descriptor_t
**media
;
183 media
= cache_get_descriptors(DM_MEDIA
, errp
);
188 if (filter
!= NULL
&& filter
[0] != DM_FILTER_END
) {
189 descriptor_t
**found
;
191 found
= apply_filter(media
, filter
, errp
);
203 media_get_name(descriptor_t
*desc
)
210 media_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
212 /* There are no stat types defined for media */
218 media_make_descriptors()
222 char mname
[MAXPATHLEN
];
224 dp
= cache_get_disklist();
226 if (media_read_name(dp
, mname
, sizeof (mname
))) {
227 cache_load_desc(DM_MEDIA
, dp
, mname
, NULL
, &error
);
240 * Read the media information.
243 media_read_info(int fd
, struct dk_minfo
*minfo
)
248 minfo
->dki_media_type
= 0;
251 * This ioctl can fail if the media is not loaded or spun up.
252 * Retrying can sometimes succeed since the first ioctl will have
253 * started the media before the ioctl timed out so the media may be
254 * spun up on the subsequent attempt.
256 while ((status
= ioctl(fd
, DKIOCGMEDIAINFO
, minfo
)) < 0) {
258 if (tries
>= IOCTLRETRIES
) {
261 (void) sleep(IOCTLRETRYINTERVAL
);
271 /* return 1 if there is media, 0 if not. */
273 media_read_name(disk_t
*dp
, char *mname
, int size
)
277 if (!dp
->removable
) {
278 /* not removable, so media name is devid */
279 if (dp
->device_id
!= NULL
) {
280 (void) strlcpy(mname
, dp
->device_id
, size
);
285 /* This is a removable media drive. */
286 return (get_rmm_name(dp
, mname
, size
));
289 static descriptor_t
**
290 apply_filter(descriptor_t
**media
, int filter
[], int *errp
)
292 descriptor_t
**found
;
297 /* count the number of media in the snapshot */
298 for (i
= 0; media
[i
]; i
++) {
302 found
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
305 cache_free_descriptors(media
);
310 for (i
= 0; media
[i
]; i
++) {
312 struct dk_minfo minfo
;
314 if ((fd
= drive_open_disk(media
[i
]->p
.disk
, NULL
, 0)) < 0) {
318 if (media_read_info(fd
, &minfo
)) {
323 mtype
= get_media_type(minfo
.dki_media_type
);
326 for (j
= 0; filter
[j
] != DM_FILTER_END
; j
++) {
327 if (mtype
== filter
[j
]) {
328 found
[pos
++] = media
[i
];
335 cache_free_descriptor(media
[i
]);
347 /* return 1 if the media descriptor is still valid, 0 if not. */
349 desc_ok(descriptor_t
*dp
)
351 /* First verify the media name for removable media */
352 if (dp
->p
.disk
->removable
) {
353 char mname
[MAXPATHLEN
];
355 if (!media_read_name(dp
->p
.disk
, mname
, sizeof (mname
))) {
360 return (libdiskmgt_str_eq(dp
->name
, NULL
));
362 return (libdiskmgt_str_eq(dp
->name
, mname
));
370 get_attrs(disk_t
*dp
, int fd
, nvlist_t
*attrs
)
372 struct dk_minfo minfo
;
373 struct dk_geom geometry
;
379 bzero(&minfo
, sizeof (struct dk_minfo
));
381 /* The first thing to do is read the media */
382 if (!media_read_info(fd
, &minfo
)) {
386 if (partition_has_fdisk(dp
, fd
)) {
387 if (nvlist_add_boolean(attrs
, DM_FDISK
) != 0) {
393 if (nvlist_add_boolean(attrs
, DM_REMOVABLE
) != 0) {
397 if (nvlist_add_boolean(attrs
, DM_LOADED
) != 0) {
402 if (nvlist_add_uint64(attrs
, DM_SIZE
, minfo
.dki_capacity
) != 0) {
406 if (nvlist_add_uint32(attrs
, DM_BLOCKSIZE
, minfo
.dki_lbsize
) != 0) {
410 if (nvlist_add_uint32(attrs
, DM_MTYPE
,
411 get_media_type(minfo
.dki_media_type
)) != 0) {
415 /* only for disks < 1TB and x86 */
416 #if defined(i386) || defined(__amd64)
417 if (ioctl(fd
, DKIOCG_PHYGEOM
, &geometry
) >= 0) {
420 if (ioctl(fd
, DKIOCGGEOM
, &geometry
) >= 0) {
424 if (nvlist_add_uint64(attrs
, DM_START
, 0) != 0) {
427 if (nvlist_add_uint64(attrs
, DM_NACCESSIBLE
,
428 geometry
.dkg_ncyl
* geometry
.dkg_nhead
* geometry
.dkg_nsect
)
432 if (nvlist_add_uint32(attrs
, DM_NCYLINDERS
, geometry
.dkg_ncyl
)
436 if (nvlist_add_uint32(attrs
, DM_NPHYSCYLINDERS
,
437 geometry
.dkg_pcyl
) != 0) {
440 if (nvlist_add_uint32(attrs
, DM_NALTCYLINDERS
,
441 geometry
.dkg_acyl
) != 0) {
444 if (nvlist_add_uint32(attrs
, DM_NHEADS
,
445 geometry
.dkg_nhead
) != 0) {
448 if (nvlist_add_uint32(attrs
, DM_NSECTORS
, geometry
.dkg_nsect
)
452 if (nvlist_add_uint32(attrs
, DM_NACTUALCYLINDERS
,
453 geometry
.dkg_ncyl
) != 0) {
457 if (read_extvtoc(fd
, &vtoc
) >= 0 && vtoc
.v_volume
[0] != 0) {
458 char label
[LEN_DKL_VVOL
+ 1];
460 (void) snprintf(label
, sizeof (label
), "%.*s",
461 LEN_DKL_VVOL
, vtoc
.v_volume
);
462 if (nvlist_add_string(attrs
, DM_LABEL
, label
) != 0) {
468 /* check for disks > 1TB for accessible size */
471 if (efi_alloc_and_read(fd
, &efip
) >= 0) {
472 diskaddr_t p8size
= 0;
474 if (nvlist_add_boolean(attrs
, DM_EFI
) != 0) {
477 if (nvlist_add_uint64(attrs
, DM_START
,
478 efip
->efi_first_u_lba
) != 0) {
481 /* partition 8 is reserved on EFI labels */
482 if (efip
->efi_nparts
>= 9) {
483 p8size
= efip
->efi_parts
[8].p_size
;
485 if (nvlist_add_uint64(attrs
, DM_NACCESSIBLE
,
486 (efip
->efi_last_u_lba
- p8size
) -
487 efip
->efi_first_u_lba
) != 0) {
498 get_media_type(uint_t media_type
)
500 switch (media_type
) {
502 return (DM_MT_UNKNOWN
);
504 return (DM_MT_MO_ERASABLE
);
505 case DK_MO_WRITEONCE
:
506 return (DM_MT_MO_WRITEONCE
);
508 return (DM_MT_AS_MO
);
510 return (DM_MT_CDROM
);
516 return (DM_MT_DVDROM
);
520 return (DM_MT_DVDRAM
);
522 return (DM_MT_FIXED
);
524 return (DM_MT_FLOPPY
);
530 return (DM_MT_UNKNOWN
);
535 * This function handles removable media.
538 get_rmm_name(disk_t
*dp
, char *mname
, int size
)
545 if ((fd
= drive_open_disk(dp
, NULL
, 0)) >= 0) {
546 struct dk_minfo minfo
;
548 if ((loaded
= media_read_info(fd
, &minfo
))) {
551 if (read_extvtoc(fd
, &vtoc
) >= 0) {
552 if (vtoc
.v_volume
[0] != NULL
) {
553 if (LEN_DKL_VVOL
< size
) {
554 (void) strlcpy(mname
,
558 (void) strlcpy(mname
,
559 vtoc
.v_volume
, size
);