dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libdiskmgt / common / media.c
blob7487e931e8707d880e5f20268372a595ba231790
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <fcntl.h>
27 #include <libdevinfo.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <stropts.h>
33 #include <sys/dkio.h>
34 #include <sys/sunddi.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <sys/vtoc.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[],
48 int *errp);
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.
57 descriptor_t **
58 media_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type,
59 int *errp)
61 if (!desc_ok(desc)) {
62 *errp = ENODEV;
63 return (NULL);
66 switch (type) {
67 case DM_DRIVE:
68 return (drive_get_assocs(desc, errp));
69 case DM_PARTITION:
70 return (partition_get_assocs(desc, errp));
71 case DM_SLICE:
72 return (slice_get_assocs(desc, errp));
75 *errp = EINVAL;
76 return (NULL);
80 * Get the media descriptors for the given drive/partition/slice.
82 descriptor_t **
83 media_get_assocs(descriptor_t *dp, int *errp)
85 descriptor_t **media;
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.
91 * require media.
93 if (dp->type == DM_DRIVE) {
94 return (libdiskmgt_empty_desc_array(errp));
95 } else {
96 *errp = ENODEV;
97 return (NULL);
101 /* make the snapshot */
102 media = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
103 if (media == NULL) {
104 *errp = ENOMEM;
105 return (NULL);
108 media[0] = cache_get_desc(DM_MEDIA, dp->p.disk, mname, NULL, errp);
109 if (*errp != 0) {
110 free(media);
111 return (NULL);
113 media[1] = NULL;
115 *errp = 0;
116 return (media);
119 nvlist_t *
120 media_get_attributes(descriptor_t *dp, int *errp)
122 nvlist_t *attrs = NULL;
123 int fd;
125 if (!desc_ok(dp)) {
126 *errp = ENODEV;
127 return (NULL);
130 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
131 *errp = ENOMEM;
132 return (NULL);
135 fd = drive_open_disk(dp->p.disk, NULL, 0);
137 if ((*errp = get_attrs(dp->p.disk, fd, attrs)) != 0) {
138 nvlist_free(attrs);
139 attrs = NULL;
142 if (fd >= 0) {
143 (void) close(fd);
146 return (attrs);
149 descriptor_t *
150 media_get_descriptor_by_name(char *name, int *errp)
152 descriptor_t **media;
153 int i;
154 descriptor_t *medium = NULL;
156 media = cache_get_descriptors(DM_MEDIA, errp);
157 if (*errp != 0) {
158 return (NULL);
161 for (i = 0; media[i]; i++) {
162 if (libdiskmgt_str_eq(name, media[i]->name)) {
163 medium = media[i];
164 } else {
165 /* clean up the unused descriptors */
166 cache_free_descriptor(media[i]);
169 free(media);
171 if (medium == NULL) {
172 *errp = ENODEV;
175 return (medium);
178 descriptor_t **
179 media_get_descriptors(int filter[], int *errp)
181 descriptor_t **media;
183 media = cache_get_descriptors(DM_MEDIA, errp);
184 if (*errp != 0) {
185 return (NULL);
188 if (filter != NULL && filter[0] != DM_FILTER_END) {
189 descriptor_t **found;
191 found = apply_filter(media, filter, errp);
192 if (*errp != 0) {
193 media = NULL;
194 } else {
195 media = found;
199 return (media);
202 char *
203 media_get_name(descriptor_t *desc)
205 return (desc->name);
208 /* ARGSUSED */
209 nvlist_t *
210 media_get_stats(descriptor_t *dp, int stat_type, int *errp)
212 /* There are no stat types defined for media */
213 *errp = EINVAL;
214 return (NULL);
218 media_make_descriptors()
220 int error;
221 disk_t *dp;
222 char mname[MAXPATHLEN];
224 dp = cache_get_disklist();
225 while (dp != NULL) {
226 if (media_read_name(dp, mname, sizeof (mname))) {
227 cache_load_desc(DM_MEDIA, dp, mname, NULL, &error);
228 if (error != 0) {
229 return (error);
233 dp = dp->next;
236 return (0);
240 * Read the media information.
243 media_read_info(int fd, struct dk_minfo *minfo)
245 int status;
246 int tries = 0;
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) {
257 tries++;
258 if (tries >= IOCTLRETRIES) {
259 break;
261 (void) sleep(IOCTLRETRYINTERVAL);
264 if (status < 0) {
265 return (0);
268 return (1);
271 /* return 1 if there is media, 0 if not. */
273 media_read_name(disk_t *dp, char *mname, int size)
275 mname[0] = 0;
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);
282 return (1);
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;
293 int i;
294 int cnt = 0;
295 int pos;
297 /* count the number of media in the snapshot */
298 for (i = 0; media[i]; i++) {
299 cnt++;
302 found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
303 if (found == NULL) {
304 *errp = ENOMEM;
305 cache_free_descriptors(media);
306 return (NULL);
309 pos = 0;
310 for (i = 0; media[i]; i++) {
311 int fd;
312 struct dk_minfo minfo;
314 if ((fd = drive_open_disk(media[i]->p.disk, NULL, 0)) < 0) {
315 continue;
318 if (media_read_info(fd, &minfo)) {
319 int mtype;
320 int j;
321 int match;
323 mtype = get_media_type(minfo.dki_media_type);
325 match = 0;
326 for (j = 0; filter[j] != DM_FILTER_END; j++) {
327 if (mtype == filter[j]) {
328 found[pos++] = media[i];
329 match = 1;
330 break;
334 if (!match) {
335 cache_free_descriptor(media[i]);
338 (void) close(fd);
340 found[pos] = NULL;
341 free(media);
343 *errp = 0;
344 return (found);
347 /* return 1 if the media descriptor is still valid, 0 if not. */
348 static int
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))) {
356 return (0);
359 if (mname[0] == 0) {
360 return (libdiskmgt_str_eq(dp->name, NULL));
361 } else {
362 return (libdiskmgt_str_eq(dp->name, mname));
366 return (1);
369 static int
370 get_attrs(disk_t *dp, int fd, nvlist_t *attrs)
372 struct dk_minfo minfo;
373 struct dk_geom geometry;
375 if (fd < 0) {
376 return (ENODEV);
379 bzero(&minfo, sizeof (struct dk_minfo));
381 /* The first thing to do is read the media */
382 if (!media_read_info(fd, &minfo)) {
383 return (ENODEV);
386 if (partition_has_fdisk(dp, fd)) {
387 if (nvlist_add_boolean(attrs, DM_FDISK) != 0) {
388 return (ENOMEM);
392 if (dp->removable) {
393 if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) {
394 return (ENOMEM);
397 if (nvlist_add_boolean(attrs, DM_LOADED) != 0) {
398 return (ENOMEM);
402 if (nvlist_add_uint64(attrs, DM_SIZE, minfo.dki_capacity) != 0) {
403 return (ENOMEM);
406 if (nvlist_add_uint32(attrs, DM_BLOCKSIZE, minfo.dki_lbsize) != 0) {
407 return (ENOMEM);
410 if (nvlist_add_uint32(attrs, DM_MTYPE,
411 get_media_type(minfo.dki_media_type)) != 0) {
412 return (ENOMEM);
415 /* only for disks < 1TB and x86 */
416 #if defined(i386) || defined(__amd64)
417 if (ioctl(fd, DKIOCG_PHYGEOM, &geometry) >= 0) {
418 #else
419 /* sparc call */
420 if (ioctl(fd, DKIOCGGEOM, &geometry) >= 0) {
421 #endif
422 struct extvtoc vtoc;
424 if (nvlist_add_uint64(attrs, DM_START, 0) != 0) {
425 return (ENOMEM);
427 if (nvlist_add_uint64(attrs, DM_NACCESSIBLE,
428 geometry.dkg_ncyl * geometry.dkg_nhead * geometry.dkg_nsect)
429 != 0) {
430 return (ENOMEM);
432 if (nvlist_add_uint32(attrs, DM_NCYLINDERS, geometry.dkg_ncyl)
433 != 0) {
434 return (ENOMEM);
436 if (nvlist_add_uint32(attrs, DM_NPHYSCYLINDERS,
437 geometry.dkg_pcyl) != 0) {
438 return (ENOMEM);
440 if (nvlist_add_uint32(attrs, DM_NALTCYLINDERS,
441 geometry.dkg_acyl) != 0) {
442 return (ENOMEM);
444 if (nvlist_add_uint32(attrs, DM_NHEADS,
445 geometry.dkg_nhead) != 0) {
446 return (ENOMEM);
448 if (nvlist_add_uint32(attrs, DM_NSECTORS, geometry.dkg_nsect)
449 != 0) {
450 return (ENOMEM);
452 if (nvlist_add_uint32(attrs, DM_NACTUALCYLINDERS,
453 geometry.dkg_ncyl) != 0) {
454 return (ENOMEM);
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) {
463 return (ENOMEM);
467 } else {
468 /* check for disks > 1TB for accessible size */
469 struct dk_gpt *efip;
471 if (efi_alloc_and_read(fd, &efip) >= 0) {
472 diskaddr_t p8size = 0;
474 if (nvlist_add_boolean(attrs, DM_EFI) != 0) {
475 return (ENOMEM);
477 if (nvlist_add_uint64(attrs, DM_START,
478 efip->efi_first_u_lba) != 0) {
479 return (ENOMEM);
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) {
488 efi_free(efip);
489 return (ENOMEM);
491 efi_free(efip);
494 return (0);
497 static int
498 get_media_type(uint_t media_type)
500 switch (media_type) {
501 case DK_UNKNOWN:
502 return (DM_MT_UNKNOWN);
503 case DK_MO_ERASABLE:
504 return (DM_MT_MO_ERASABLE);
505 case DK_MO_WRITEONCE:
506 return (DM_MT_MO_WRITEONCE);
507 case DK_AS_MO:
508 return (DM_MT_AS_MO);
509 case DK_CDROM:
510 return (DM_MT_CDROM);
511 case DK_CDR:
512 return (DM_MT_CDR);
513 case DK_CDRW:
514 return (DM_MT_CDRW);
515 case DK_DVDROM:
516 return (DM_MT_DVDROM);
517 case DK_DVDR:
518 return (DM_MT_DVDR);
519 case DK_DVDRAM:
520 return (DM_MT_DVDRAM);
521 case DK_FIXED_DISK:
522 return (DM_MT_FIXED);
523 case DK_FLOPPY:
524 return (DM_MT_FLOPPY);
525 case DK_ZIP:
526 return (DM_MT_ZIP);
527 case DK_JAZ:
528 return (DM_MT_JAZ);
529 default:
530 return (DM_MT_UNKNOWN);
535 * This function handles removable media.
537 static int
538 get_rmm_name(disk_t *dp, char *mname, int size)
540 int loaded;
541 int fd;
543 loaded = 0;
545 if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) {
546 struct dk_minfo minfo;
548 if ((loaded = media_read_info(fd, &minfo))) {
549 struct extvtoc vtoc;
551 if (read_extvtoc(fd, &vtoc) >= 0) {
552 if (vtoc.v_volume[0] != '\0') {
553 if (LEN_DKL_VVOL < size) {
554 (void) strlcpy(mname,
555 vtoc.v_volume,
556 LEN_DKL_VVOL);
557 } else {
558 (void) strlcpy(mname,
559 vtoc.v_volume, size);
565 (void) close(fd);
568 return (loaded);