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 <fcntl.h> 30 #include <libdevinfo.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <stropts.h> 36 #include <sys/dkio.h> 37 #include <sys/sunddi.h> 38 #include <sys/types.h> 39 #include <unistd.h> 40 #include <sys/vtoc.h> 41 #include <volmgt.h> 42 #include <sys/efi_partition.h> 43 44 #include "libdiskmgt.h" 45 #include "disks_private.h" 46 #include "partition.h" 47 48 #define IOCTLRETRIES 2 49 #define IOCTLRETRYINTERVAL 1 50 51 static descriptor_t **apply_filter(descriptor_t **media, int filter[], 52 int *errp); 53 static int get_attrs(disk_t *dp, int fd, nvlist_t *attrs); 54 static int get_non_volm_name(disk_t *dp, char *mname, int size); 55 static int get_media_type(uint_t media_type); 56 static int desc_ok(descriptor_t *dp); 57 58 /* 59 * This function gets the descriptors we are associated with. 60 */ 61 descriptor_t ** 62 media_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type, 63 int *errp) 64 { 65 if (!desc_ok(desc)) { 66 *errp = ENODEV; 67 return (NULL); 68 } 69 70 switch (type) { 71 case DM_DRIVE: 72 return (drive_get_assocs(desc, errp)); 73 case DM_PARTITION: 74 return (partition_get_assocs(desc, errp)); 75 case DM_SLICE: 76 return (slice_get_assocs(desc, errp)); 77 } 78 79 *errp = EINVAL; 80 return (NULL); 81 } 82 83 /* 84 * Get the media descriptors for the given drive/partition/slice. 85 */ 86 descriptor_t ** 87 media_get_assocs(descriptor_t *dp, int *errp) 88 { 89 descriptor_t **media; 90 char mname[MAXPATHLEN]; 91 92 if (!media_read_name(dp->p.disk, mname, sizeof (mname))) { 93 /* For drives, this means no media but slice/part. require media. */ 94 if (dp->type == DM_DRIVE) { 95 return (libdiskmgt_empty_desc_array(errp)); 96 } else { 97 *errp = ENODEV; 98 return (NULL); 99 } 100 } 101 102 /* make the snapshot */ 103 media = (descriptor_t **)calloc(2, sizeof (descriptor_t *)); 104 if (media == NULL) { 105 *errp = ENOMEM; 106 return (NULL); 107 } 108 109 media[0] = cache_get_desc(DM_MEDIA, dp->p.disk, mname, NULL, errp); 110 if (*errp != 0) { 111 free(media); 112 return (NULL); 113 } 114 media[1] = NULL; 115 116 *errp = 0; 117 return (media); 118 } 119 120 nvlist_t * 121 media_get_attributes(descriptor_t *dp, int *errp) 122 { 123 nvlist_t *attrs = NULL; 124 int fd; 125 126 if (!desc_ok(dp)) { 127 *errp = ENODEV; 128 return (NULL); 129 } 130 131 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) { 132 *errp = ENOMEM; 133 return (NULL); 134 } 135 136 fd = drive_open_disk(dp->p.disk, NULL, 0); 137 138 if ((*errp = get_attrs(dp->p.disk, fd, attrs)) != 0) { 139 nvlist_free(attrs); 140 attrs = NULL; 141 } 142 143 if (fd >= 0) { 144 (void) close(fd); 145 } 146 147 return (attrs); 148 } 149 150 descriptor_t * 151 media_get_descriptor_by_name(char *name, int *errp) 152 { 153 descriptor_t **media; 154 int i; 155 descriptor_t *medium = NULL; 156 157 media = cache_get_descriptors(DM_MEDIA, errp); 158 if (*errp != 0) { 159 return (NULL); 160 } 161 162 for (i = 0; media[i]; i++) { 163 if (libdiskmgt_str_eq(name, media[i]->name)) { 164 medium = media[i]; 165 } else { 166 /* clean up the unused descriptors */ 167 cache_free_descriptor(media[i]); 168 } 169 } 170 free(media); 171 172 if (medium == NULL) { 173 *errp = ENODEV; 174 } 175 176 return (medium); 177 } 178 179 descriptor_t ** 180 media_get_descriptors(int filter[], int *errp) 181 { 182 descriptor_t **media; 183 184 media = cache_get_descriptors(DM_MEDIA, errp); 185 if (*errp != 0) { 186 return (NULL); 187 } 188 189 if (filter != NULL && filter[0] != DM_FILTER_END) { 190 descriptor_t **found; 191 192 found = apply_filter(media, filter, errp); 193 if (*errp != 0) { 194 media = NULL; 195 } else { 196 media = found; 197 } 198 } 199 200 return (media); 201 } 202 203 char * 204 media_get_name(descriptor_t *desc) 205 { 206 return (desc->name); 207 } 208 209 /* ARGSUSED */ 210 nvlist_t * 211 media_get_stats(descriptor_t *dp, int stat_type, int *errp) 212 { 213 /* There are no stat types defined for media */ 214 *errp = EINVAL; 215 return (NULL); 216 } 217 218 /* 219 * Get the removable media volume manager devpath for the disk. This is the 220 * name we need to open that will work with vold. 221 * Return 1 if under volm control, 0 if not under volm control. 222 * The string in mediapath will be empty if the drive is under volm control 223 * but there is no media loaded. 224 */ 225 int 226 media_get_volm_path(disk_t *diskp, char *mediapath, int size) 227 { 228 char vname[MAXPATHLEN]; 229 char *volname; 230 char *media_name; 231 232 if (!diskp->removable || !volmgt_running()) { 233 return (0); 234 } 235 236 /* 237 * The volume manager is running, so we have to check if this removable 238 * drive is under volm control or not. 239 */ 240 241 /* 242 * We must check if this drive is under volume management control and 243 * what devpath to use. 244 * Note that we have to do this every time for drives that are not 245 * under the control of the volume manager, since the volume manager 246 * might have taken control since the last time we checked. 247 */ 248 if (diskp->volm_path_set == 0) { 249 alias_t *ap; 250 slice_t *dp; 251 252 if ((ap = diskp->aliases) == NULL) { 253 return (0); 254 } 255 256 /* Check each devpath to see if it is under volm control. */ 257 dp = ap->devpaths; 258 while (dp != NULL) { 259 slice_rdsk2dsk(dp->devpath, vname, sizeof (vname)); 260 if (volmgt_inuse(vname)) { 261 break; 262 } 263 264 dp = dp->next; 265 } 266 267 if (dp != NULL) { 268 /* Volume manager is managing the devpath that dp points to. */ 269 diskp->volm_path = dp->devpath; 270 diskp->volm_path_set = 1; 271 } 272 } 273 274 if (diskp->volm_path_set == 0) { 275 /* The volume manager is not managing any of the devpaths. */ 276 return (0); 277 } 278 279 if (dm_debug > 1) { 280 (void) fprintf(stderr, "INFO: chk vol: %s\n", diskp->volm_path); 281 } 282 283 slice_rdsk2dsk(diskp->volm_path, vname, sizeof (vname)); 284 volname = volmgt_symname(vname); 285 if (volname == NULL) { 286 mediapath[0] = 0; 287 return (1); 288 } 289 290 media_name = media_findname(volname); 291 free(volname); 292 if (media_name == NULL) { 293 mediapath[0] = 0; 294 return (1); 295 } 296 297 (void) strlcpy(mediapath, media_name, size); 298 free(media_name); 299 return (1); 300 } 301 302 int 303 media_make_descriptors() 304 { 305 int error; 306 disk_t *dp; 307 char mname[MAXPATHLEN]; 308 309 dp = cache_get_disklist(); 310 while (dp != NULL) { 311 if (media_read_name(dp, mname, sizeof (mname))) { 312 cache_load_desc(DM_MEDIA, dp, mname, NULL, &error); 313 if (error != 0) { 314 return (error); 315 } 316 } 317 318 dp = dp->next; 319 } 320 321 return (0); 322 } 323 324 /* 325 * Read the media information. 326 */ 327 int 328 media_read_info(int fd, struct dk_minfo *minfo) 329 { 330 int status; 331 int tries = 0; 332 333 minfo->dki_media_type = 0; 334 335 /* 336 * This ioctl can fail if the media is not loaded or spun up. 337 * Retrying can sometimes succeed since the first ioctl will have 338 * started the media before the ioctl timed out so the media may be 339 * spun up on the subsequent attempt. 340 */ 341 while ((status = ioctl(fd, DKIOCGMEDIAINFO, minfo)) < 0) { 342 tries++; 343 if (tries >= IOCTLRETRIES) { 344 break; 345 } 346 (void) sleep(IOCTLRETRYINTERVAL); 347 } 348 349 if (status < 0) { 350 return (0); 351 } 352 353 return (1); 354 } 355 356 /* return 1 if there is media, 0 if not. */ 357 int 358 media_read_name(disk_t *dp, char *mname, int size) 359 { 360 int under_volm; 361 char rmmedia_devpath[MAXPATHLEN]; 362 363 mname[0] = 0; 364 365 if (!dp->removable) { 366 /* not removable, so media name is devid */ 367 if (dp->device_id != NULL) { 368 (void) strlcpy(mname, dp->device_id, size); 369 } 370 return (1); 371 } 372 373 /* This is a removable media drive. */ 374 375 /* Get 1 if under volm control, 0 if not */ 376 under_volm = media_get_volm_path(dp, rmmedia_devpath, 377 sizeof (rmmedia_devpath)); 378 379 if (under_volm) { 380 /* under volm control */ 381 if (rmmedia_devpath[0] == 0) { 382 /* no media */ 383 return (0); 384 } 385 (void) strlcpy(mname, rmmedia_devpath, size); 386 return (1); 387 388 } else { 389 /* not under volm control */ 390 return (get_non_volm_name(dp, mname, size)); 391 } 392 } 393 394 static descriptor_t ** 395 apply_filter(descriptor_t **media, int filter[], int *errp) 396 { 397 descriptor_t **found; 398 int i; 399 int cnt = 0; 400 int pos; 401 402 /* count the number of media in the snapshot */ 403 for (i = 0; media[i]; i++) { 404 cnt++; 405 } 406 407 found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 408 if (found == NULL) { 409 *errp = ENOMEM; 410 cache_free_descriptors(media); 411 return (NULL); 412 } 413 414 pos = 0; 415 for (i = 0; media[i]; i++) { 416 int fd; 417 struct dk_minfo minfo; 418 419 if ((fd = drive_open_disk(media[i]->p.disk, NULL, 0)) < 0) { 420 continue; 421 } 422 423 if (media_read_info(fd, &minfo)) { 424 int mtype; 425 int j; 426 int match; 427 428 mtype = get_media_type(minfo.dki_media_type); 429 430 match = 0; 431 for (j = 0; filter[j] != DM_FILTER_END; j++) { 432 if (mtype == filter[j]) { 433 found[pos++] = media[i]; 434 match = 1; 435 break; 436 } 437 } 438 439 if (!match) { 440 cache_free_descriptor(media[i]); 441 } 442 } 443 (void) close(fd); 444 } 445 found[pos] = NULL; 446 free(media); 447 448 *errp = 0; 449 return (found); 450 } 451 452 /* return 1 if the media descriptor is still valid, 0 if not. */ 453 static int 454 desc_ok(descriptor_t *dp) 455 { 456 /* First verify the media name for removable media */ 457 if (dp->p.disk->removable) { 458 char mname[MAXPATHLEN]; 459 460 if (!media_read_name(dp->p.disk, mname, sizeof (mname))) { 461 return (0); 462 } 463 464 if (mname[0] == 0) { 465 return (libdiskmgt_str_eq(dp->name, NULL)); 466 } else { 467 return (libdiskmgt_str_eq(dp->name, mname)); 468 } 469 } 470 471 return (1); 472 } 473 474 static int 475 get_attrs(disk_t *dp, int fd, nvlist_t *attrs) 476 { 477 struct dk_minfo minfo; 478 struct dk_geom geometry; 479 480 if (fd < 0) { 481 return (ENODEV); 482 } 483 484 bzero(&minfo, sizeof (struct dk_minfo)); 485 486 /* The first thing to do is read the media */ 487 if (!media_read_info(fd, &minfo)) { 488 return (ENODEV); 489 } 490 491 if (partition_has_fdisk(dp, fd)) { 492 if (nvlist_add_boolean(attrs, DM_FDISK) != 0) { 493 return (ENOMEM); 494 } 495 } 496 497 if (dp->removable) { 498 if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) { 499 return (ENOMEM); 500 } 501 502 if (nvlist_add_boolean(attrs, DM_LOADED) != 0) { 503 return (ENOMEM); 504 } 505 } 506 507 if (nvlist_add_uint64(attrs, DM_SIZE, minfo.dki_capacity) != 0) { 508 return (ENOMEM); 509 } 510 511 if (nvlist_add_uint32(attrs, DM_BLOCKSIZE, minfo.dki_lbsize) != 0) { 512 return (ENOMEM); 513 } 514 515 if (nvlist_add_uint32(attrs, DM_MTYPE, 516 get_media_type(minfo.dki_media_type)) != 0) { 517 return (ENOMEM); 518 } 519 520 /* only for disks < 1TB */ 521 if (ioctl(fd, DKIOCGGEOM, &geometry) >= 0) { 522 struct vtoc vtoc; 523 524 if (nvlist_add_uint64(attrs, DM_START, 0) != 0) { 525 return (ENOMEM); 526 } 527 if (nvlist_add_uint64(attrs, DM_NACCESSIBLE, 528 geometry.dkg_ncyl * geometry.dkg_nhead * geometry.dkg_nsect) 529 != 0) { 530 return (ENOMEM); 531 } 532 if (nvlist_add_uint32(attrs, DM_NCYLINDERS, geometry.dkg_ncyl) 533 != 0) { 534 return (ENOMEM); 535 } 536 if (nvlist_add_uint32(attrs, DM_NPHYSCYLINDERS, geometry.dkg_pcyl) 537 != 0) { 538 return (ENOMEM); 539 } 540 if (nvlist_add_uint32(attrs, DM_NALTCYLINDERS, geometry.dkg_acyl) 541 != 0) { 542 return (ENOMEM); 543 } 544 if (nvlist_add_uint32(attrs, DM_NHEADS, geometry.dkg_nhead) != 0) { 545 return (ENOMEM); 546 } 547 if (nvlist_add_uint32(attrs, DM_NSECTORS, geometry.dkg_nsect) 548 != 0) { 549 return (ENOMEM); 550 } 551 552 if (read_vtoc(fd, &vtoc) >= 0 && vtoc.v_volume[0] != 0) { 553 char label[LEN_DKL_VVOL + 1]; 554 555 (void) snprintf(label, sizeof (label), "%.*s", LEN_DKL_VVOL, 556 vtoc.v_volume); 557 if (nvlist_add_string(attrs, DM_LABEL, label) != 0) { 558 return (ENOMEM); 559 } 560 } 561 562 } else { 563 /* check for disks > 1TB for accessible size */ 564 struct dk_gpt *efip; 565 566 if (efi_alloc_and_read(fd, &efip) >= 0) { 567 diskaddr_t p8size = 0; 568 569 if (nvlist_add_boolean(attrs, DM_EFI) != 0) { 570 return (ENOMEM); 571 } 572 if (nvlist_add_uint64(attrs, DM_START, efip->efi_first_u_lba) 573 != 0) { 574 return (ENOMEM); 575 } 576 /* partition 8 is reserved on EFI labels */ 577 if (efip->efi_nparts >= 9) { 578 p8size = efip->efi_parts[8].p_size; 579 } 580 if (nvlist_add_uint64(attrs, DM_NACCESSIBLE, 581 (efip->efi_last_u_lba - p8size) - efip->efi_first_u_lba) 582 != 0) { 583 efi_free(efip); 584 return (ENOMEM); 585 } 586 efi_free(efip); 587 } 588 } 589 590 /* This ioctl seems to be mainly for intel-based drives. */ 591 if (ioctl(fd, DKIOCG_PHYGEOM, &geometry) >= 0) { 592 if (nvlist_add_uint32(attrs, DM_NACTUALCYLINDERS, geometry.dkg_ncyl) 593 != 0) { 594 return (ENOMEM); 595 } 596 } 597 598 return (0); 599 } 600 601 static int 602 get_media_type(uint_t media_type) 603 { 604 switch (media_type) { 605 case DK_UNKNOWN: 606 return (DM_MT_UNKNOWN); 607 case DK_MO_ERASABLE: 608 return (DM_MT_MO_ERASABLE); 609 case DK_MO_WRITEONCE: 610 return (DM_MT_MO_WRITEONCE); 611 case DK_AS_MO: 612 return (DM_MT_AS_MO); 613 case DK_CDROM: 614 return (DM_MT_CDROM); 615 case DK_CDR: 616 return (DM_MT_CDR); 617 case DK_CDRW: 618 return (DM_MT_CDRW); 619 case DK_DVDROM: 620 return (DM_MT_DVDROM); 621 case DK_DVDR: 622 return (DM_MT_DVDR); 623 case DK_DVDRAM: 624 return (DM_MT_DVDRAM); 625 case DK_FIXED_DISK: 626 return (DM_MT_FIXED); 627 case DK_FLOPPY: 628 return (DM_MT_FLOPPY); 629 case DK_ZIP: 630 return (DM_MT_ZIP); 631 case DK_JAZ: 632 return (DM_MT_JAZ); 633 default: 634 return (DM_MT_UNKNOWN); 635 } 636 } 637 638 /* 639 * This function handles removable media not under volume management. 640 */ 641 static int 642 get_non_volm_name(disk_t *dp, char *mname, int size) 643 { 644 int loaded; 645 int fd; 646 647 loaded = 0; 648 649 if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) { 650 struct dk_minfo minfo; 651 652 if ((loaded = media_read_info(fd, &minfo))) { 653 struct vtoc vtoc; 654 655 if (read_vtoc(fd, &vtoc) >= 0) { 656 if (vtoc.v_volume[0] != NULL) { 657 if (LEN_DKL_VVOL < size) { 658 (void) strlcpy(mname, vtoc.v_volume, LEN_DKL_VVOL); 659 } else { 660 (void) strlcpy(mname, vtoc.v_volume, size); 661 } 662 } 663 } 664 } 665 666 (void) close(fd); 667 } 668 669 return (loaded); 670 } 671