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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * This file contains the code relating to label manipulation. 29 */ 30 31 #include <string.h> 32 #include <stdlib.h> 33 #include <memory.h> 34 #include <sys/isa_defs.h> 35 #include <sys/efi_partition.h> 36 #include <sys/vtoc.h> 37 #include <sys/uuid.h> 38 #include <errno.h> 39 #include <devid.h> 40 #include <libdevinfo.h> 41 #include "global.h" 42 #include "label.h" 43 #include "misc.h" 44 #include "main.h" 45 #include "partition.h" 46 #include "ctlr_scsi.h" 47 #include "checkdev.h" 48 49 #if defined(_FIRMWARE_NEEDS_FDISK) 50 #include <sys/dktp/fdisk.h> 51 #include "menu_fdisk.h" 52 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 53 54 #ifndef WD_NODE 55 #define WD_NODE 7 56 #endif 57 58 static int do_geometry_sanity_check(void); 59 static int vtoc_to_label(struct dk_label *, struct extvtoc *, 60 struct dk_geom *, struct dk_cinfo *); 61 extern int read_extvtoc(int, struct extvtoc *); 62 extern int write_extvtoc(int, struct extvtoc *); 63 static int vtoc64_to_label(struct efi_info *, struct dk_gpt *); 64 65 #ifdef DEBUG 66 static void dump_label(struct dk_label *); 67 #endif 68 69 /* 70 * This routine checks the given label to see if it is valid. 71 */ 72 int 73 checklabel(struct dk_label *label) 74 { 75 76 /* 77 * Check the magic number. 78 */ 79 if (label->dkl_magic != DKL_MAGIC) 80 return (0); 81 /* 82 * Check the checksum. 83 */ 84 if (checksum(label, CK_CHECKSUM) != 0) 85 return (0); 86 return (1); 87 } 88 89 /* 90 * This routine checks or calculates the label checksum, depending on 91 * the mode it is called in. 92 */ 93 int 94 checksum(struct dk_label *label, int mode) 95 { 96 short *sp, sum = 0; 97 short count = (sizeof (struct dk_label)) / (sizeof (short)); 98 99 /* 100 * If we are generating a checksum, don't include the checksum 101 * in the rolling xor. 102 */ 103 if (mode == CK_MAKESUM) 104 count -= 1; 105 sp = (short *)label; 106 /* 107 * Take the xor of all the half-words in the label. 108 */ 109 while (count--) { 110 sum ^= *sp++; 111 } 112 /* 113 * If we are checking the checksum, the total will be zero for 114 * a correct checksum, so we can just return the sum. 115 */ 116 if (mode == CK_CHECKSUM) 117 return (sum); 118 /* 119 * If we are generating the checksum, fill it in. 120 */ 121 else { 122 label->dkl_cksum = sum; 123 return (0); 124 } 125 } 126 127 /* 128 * This routine is used to extract the id string from the string stored 129 * in a disk label. The problem is that the string in the label has 130 * the physical characteristics of the drive appended to it. The approach 131 * is to find the beginning of the physical attributes portion of the string 132 * and truncate it there. 133 */ 134 int 135 trim_id(char *id) 136 { 137 char *c; 138 139 /* 140 * Start at the end of the string. When we match the word ' cyl', 141 * we are at the beginning of the attributes. 142 */ 143 for (c = id + strlen(id); c >= id; c--) { 144 if (strncmp(c, " cyl", strlen(" cyl")) == 0) { 145 /* 146 * Remove any white space. 147 */ 148 for (; (((*(c - 1) == ' ') || (*(c - 1) == '\t')) && 149 (c >= id)); c--) 150 ; 151 break; 152 } 153 } 154 /* 155 * If we ran off the beginning of the string, something is wrong. 156 */ 157 if (c < id) 158 return (-1); 159 /* 160 * Truncate the string. 161 */ 162 *c = '\0'; 163 return (0); 164 } 165 166 /* 167 * This routine is used by write_label() to do a quick sanity check on the 168 * supplied geometry. This is not a thorough check. 169 * 170 * The SCSI READ_CAPACITY command is used here to get the capacity of the 171 * disk. But, the available area to store data on a disk is usually less 172 * than this. So, if the specified geometry evaluates to a value which falls 173 * in this margin, then such illegal geometries can slip through the cracks. 174 */ 175 static int 176 do_geometry_sanity_check() 177 { 178 struct scsi_capacity_16 capacity; 179 180 if (uscsi_read_capacity(cur_file, &capacity)) { 181 err_print("Warning: Unable to get capacity." 182 " Cannot check geometry\n"); 183 return (0); /* Just ignore this problem */ 184 } 185 186 if (capacity.sc_capacity < ncyl * nhead * nsect) { 187 err_print("\nWarning: Current geometry overshoots " 188 "actual geometry of disk\n\n"); 189 if (check("Continue labelling disk") != 0) 190 return (-1); 191 return (0); /* Just ignore this problem */ 192 } 193 194 return (0); 195 } 196 197 /* 198 * create a clear EFI partition table when format is used 199 * to convert an SMI label to an EFI label 200 */ 201 int 202 SMI_vtoc_to_EFI(int fd, struct dk_gpt **new_vtoc) 203 { 204 int i; 205 struct dk_gpt *efi; 206 uint64_t reserved; 207 208 if (efi_alloc_and_init(fd, EFI_NUMPAR, new_vtoc) != 0) { 209 err_print("SMI vtoc to EFI failed\n"); 210 return (-1); 211 } 212 efi = *new_vtoc; 213 reserved = efi_reserved_sectors(efi); 214 215 /* 216 * create a clear EFI partition table: 217 * s0 takes the whole disk except the primary EFI lable, 218 * backup EFI labels, and the reserved partition. 219 * s1-s6 are unassigned slices. 220 */ 221 efi->efi_parts[0].p_tag = V_USR; 222 efi->efi_parts[0].p_start = efi->efi_first_u_lba; 223 efi->efi_parts[0].p_size = efi->efi_last_u_lba - efi->efi_first_u_lba 224 - reserved + 1; 225 226 /* 227 * s1-s6 are unassigned slices 228 */ 229 for (i = 1; i < efi->efi_nparts - 2; i++) { 230 efi->efi_parts[i].p_tag = V_UNASSIGNED; 231 efi->efi_parts[i].p_start = 0; 232 efi->efi_parts[i].p_size = 0; 233 } 234 235 /* 236 * the reserved slice 237 */ 238 efi->efi_parts[efi->efi_nparts - 1].p_tag = V_RESERVED; 239 efi->efi_parts[efi->efi_nparts - 1].p_start = 240 efi->efi_last_u_lba - reserved + 1; 241 efi->efi_parts[efi->efi_nparts - 1].p_size = reserved; 242 243 return (0); 244 } 245 246 /* 247 * This routine constructs and writes a label on the disk. It writes both 248 * the primary and backup labels. It assumes that there is a current 249 * partition map already defined. It also notifies the SunOS kernel of 250 * the label and partition information it has written on the disk. 251 */ 252 int 253 write_label() 254 { 255 int error = 0, head, sec; 256 struct dk_label label; 257 struct extvtoc vtoc; 258 struct dk_geom geom; 259 struct dk_gpt *vtoc64; 260 int nbackups; 261 char *new_label; 262 263 #if defined(_SUNOS_VTOC_8) 264 int i; 265 #endif /* defined(_SUNOS_VTOC_8) */ 266 267 /* 268 * Check to see if any partitions used for svm, vxvm or live upgrade 269 * are on the disk. If so, refuse to label the disk, but only 270 * if we are trying to shrink a partition in use. 271 */ 272 if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1, 273 (diskaddr_t)-1, 0, 1)) { 274 err_print("Cannot label disk when " 275 "partitions are in use as described.\n"); 276 return (-1); 277 } 278 279 /* 280 * If EFI label, then write it out to disk 281 */ 282 if (cur_label == L_TYPE_EFI) { 283 enter_critical(); 284 vtoc64 = cur_parts->etoc; 285 err_check(vtoc64); 286 if (efi_write(cur_file, vtoc64) != 0) { 287 err_print("Warning: error writing EFI.\n"); 288 error = -1; 289 } 290 291 cur_disk->disk_flags |= DSK_LABEL; 292 exit_critical(); 293 return (error); 294 } 295 296 /* 297 * Fill in a label structure with the geometry information. 298 */ 299 (void) memset((char *)&label, 0, sizeof (struct dk_label)); 300 new_label = zalloc(cur_blksz); 301 302 label.dkl_pcyl = pcyl; 303 label.dkl_ncyl = ncyl; 304 label.dkl_acyl = acyl; 305 306 #if defined(_SUNOS_VTOC_16) 307 label.dkl_bcyl = bcyl; 308 #endif /* defined(_SUNOC_VTOC_16) */ 309 310 label.dkl_nhead = nhead; 311 label.dkl_nsect = nsect; 312 label.dkl_apc = apc; 313 label.dkl_intrlv = 1; 314 label.dkl_rpm = cur_dtype->dtype_rpm; 315 316 #if defined(_SUNOS_VTOC_8) 317 /* 318 * Also fill in the current partition information. 319 */ 320 for (i = 0; i < NDKMAP; i++) { 321 label.dkl_map[i] = cur_parts->pinfo_map[i]; 322 } 323 #endif /* defined(_SUNOS_VTOC_8) */ 324 325 label.dkl_magic = DKL_MAGIC; 326 327 /* 328 * Fill in the vtoc information 329 */ 330 label.dkl_vtoc = cur_parts->vtoc; 331 332 /* 333 * Use the current label 334 */ 335 bcopy(cur_disk->v_volume, label.dkl_vtoc.v_volume, LEN_DKL_VVOL); 336 337 /* 338 * Put asciilabel in; on x86 it's in the vtoc, not the label. 339 */ 340 (void) snprintf(label.dkl_asciilabel, sizeof (label.dkl_asciilabel), 341 "%s cyl %d alt %d hd %d sec %d", 342 cur_dtype->dtype_asciilabel, ncyl, acyl, nhead, nsect); 343 344 #if defined(_SUNOS_VTOC_16) 345 /* 346 * Also add in v_sectorsz, as the driver will. 347 */ 348 label.dkl_vtoc.v_sectorsz = cur_blksz; 349 #endif /* defined(_SUNOS_VTOC_16) */ 350 351 /* 352 * Generate the correct checksum. 353 */ 354 (void) checksum(&label, CK_MAKESUM); 355 /* 356 * Convert the label into a vtoc 357 */ 358 if (label_to_vtoc(&vtoc, &label) == -1) { 359 free(new_label); 360 return (-1); 361 } 362 /* 363 * Fill in the geometry info. This is critical that 364 * we do this before writing the vtoc. 365 */ 366 bzero((caddr_t)&geom, sizeof (struct dk_geom)); 367 geom.dkg_ncyl = ncyl; 368 geom.dkg_acyl = acyl; 369 370 #if defined(_SUNOS_VTOC_16) 371 geom.dkg_bcyl = bcyl; 372 #endif /* defined(_SUNOS_VTOC_16) */ 373 374 geom.dkg_nhead = nhead; 375 geom.dkg_nsect = nsect; 376 geom.dkg_intrlv = 1; 377 geom.dkg_apc = apc; 378 geom.dkg_rpm = cur_dtype->dtype_rpm; 379 geom.dkg_pcyl = pcyl; 380 381 /* 382 * Make a quick check to see that the geometry is being 383 * written now is not way off from the actual capacity 384 * of the disk. This is only an appoximate check and 385 * is only for SCSI disks. 386 */ 387 if (SCSI && do_geometry_sanity_check() != 0) { 388 free(new_label); 389 return (-1); 390 } 391 392 /* 393 * Lock out interrupts so we do things in sync. 394 */ 395 enter_critical(); 396 /* 397 * Do the ioctl to tell the kernel the geometry. 398 */ 399 if (ioctl(cur_file, DKIOCSGEOM, &geom) == -1) { 400 err_print("Warning: error setting drive geometry.\n"); 401 error = -1; 402 } 403 /* 404 * Write the vtoc. At the time of this writing, our 405 * drivers convert the vtoc back to a label, and 406 * then write both the primary and backup labels. 407 * This is not a requirement, however, as we 408 * always use an ioctl to read the vtoc from the 409 * driver, so it can do as it likes. 410 */ 411 if (write_extvtoc(cur_file, &vtoc) != 0) { 412 err_print("Warning: error writing VTOC.\n"); 413 error = -1; 414 } 415 416 /* 417 * Calculate where the backup labels went. They are always on 418 * the last alternate cylinder, but some older drives put them 419 * on head 2 instead of the last head. They are always on the 420 * first 5 odd sectors of the appropriate track. 421 */ 422 if (cur_ctype->ctype_flags & CF_BLABEL) 423 head = 2; 424 else 425 head = nhead - 1; 426 /* 427 * Read and verify the backup labels. 428 */ 429 nbackups = 0; 430 for (sec = 1; ((sec < BAD_LISTCNT * 2 + 1) && (sec < nsect)); 431 sec += 2) { 432 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, (diskaddr_t) 433 ((chs2bn(ncyl + acyl - 1, head, sec)) 434 + solaris_offset), 1, new_label, F_NORMAL, NULL)) { 435 err_print("Warning: error reading" 436 "backup label.\n"); 437 error = -1; 438 } else { 439 if (bcmp((char *)&label, new_label, 440 sizeof (struct dk_label)) == 0) { 441 nbackups++; 442 } 443 } 444 } 445 if (nbackups != BAD_LISTCNT) { 446 err_print("Warning: %s\n", nbackups == 0 ? 447 "no backup labels" : "some backup labels incorrect"); 448 } 449 /* 450 * Mark the current disk as labelled and notify the kernel of what 451 * has happened. 452 */ 453 cur_disk->disk_flags |= DSK_LABEL; 454 455 exit_critical(); 456 free(new_label); 457 return (error); 458 } 459 460 461 /* 462 * Read the label from the disk. 463 * Do this via the read_extvtoc() library routine, then convert it to a label. 464 * We also need a DKIOCGGEOM ioctl to get the disk's geometry. 465 */ 466 int 467 read_label(int fd, struct dk_label *label) 468 { 469 struct extvtoc vtoc; 470 struct dk_geom geom; 471 struct dk_cinfo dkinfo; 472 473 if (read_extvtoc(fd, &vtoc) < 0 || 474 ioctl(fd, DKIOCGGEOM, &geom) == -1 || 475 ioctl(fd, DKIOCINFO, &dkinfo) == -1) { 476 return (-1); 477 } 478 479 return (vtoc_to_label(label, &vtoc, &geom, &dkinfo)); 480 } 481 482 int 483 get_disk_inquiry_prop(char *devpath, char **vid, char **pid, char **rid) 484 { 485 char *v, *p, *r; 486 di_node_t node; 487 int ret = -1; 488 489 node = di_init(devpath, DINFOCPYALL); 490 491 if (node == DI_NODE_NIL) 492 goto out; 493 494 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 495 "inquiry-vendor-id", &v) != 1) 496 goto out; 497 498 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 499 "inquiry-product-id", &p) != 1) 500 goto out; 501 502 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 503 "inquiry-revision-id", &r) != 1) 504 goto out; 505 506 *vid = strdup(v); 507 *pid = strdup(p); 508 *rid = strdup(r); 509 510 if (*vid == NULL || *pid == NULL || *rid == NULL) { 511 free(*vid); 512 free(*pid); 513 free(*rid); 514 goto out; 515 } 516 517 ret = 0; 518 519 out: 520 di_fini(node); 521 return (ret); 522 } 523 524 int 525 get_disk_inquiry_uscsi(int fd, char **vid, char **pid, char **rid) 526 { 527 struct scsi_inquiry inquiry; 528 529 if (uscsi_inquiry(fd, (char *)&inquiry, sizeof (inquiry))) 530 return (-1); 531 532 *vid = strndup(inquiry.inq_vid, 8); 533 *pid = strndup(inquiry.inq_pid, 16); 534 *rid = strndup(inquiry.inq_revision, 4); 535 536 if (*vid == NULL || *pid == NULL || *rid == NULL) { 537 free(*vid); 538 free(*pid); 539 free(*rid); 540 return (-1); 541 } 542 543 return (0); 544 } 545 546 int 547 get_disk_capacity(int fd, uint64_t *capacity) 548 { 549 struct dk_minfo minf; 550 struct scsi_capacity_16 cap16; 551 552 if (ioctl(fd, DKIOCGMEDIAINFO, &minf) == 0) { 553 *capacity = minf.dki_capacity * minf.dki_lbsize / cur_blksz; 554 return (0); 555 } 556 557 if (uscsi_read_capacity(fd, &cap16) == 0) { 558 *capacity = cap16.sc_capacity; 559 560 /* Since we are counting from zero, add 1 to capacity */ 561 (*capacity)++; 562 563 return (0); 564 } 565 566 err_print("Fetch Capacity failed\n"); 567 return (-1); 568 } 569 570 int 571 get_disk_inquiry_devid(int fd, char **vid, char **pid, char **rid) 572 { 573 ddi_devid_t devid; 574 char *s; 575 char *v, *p; 576 struct dk_cinfo dkinfo; 577 578 if (devid_get(fd, &devid)) { 579 if (option_msg && diag_msg) 580 err_print("devid_get failed\n"); 581 return (-1); 582 } 583 584 s = (char *)devid; 585 586 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) { 587 if (option_msg && diag_msg) 588 err_print("DKIOCINFO failed\n"); 589 return (-1); 590 } 591 592 if (dkinfo.dki_ctype != DKC_DIRECT) 593 return (-1); 594 595 v = s+12; 596 if (!(p = strchr(v, '='))) 597 return (-1); 598 p += 1; 599 600 *vid = strdup(v); 601 *pid = strdup(p); 602 *rid = strdup("0001"); 603 devid_free(devid); 604 605 if (*vid == NULL || *pid == NULL || *rid == NULL) { 606 free(*vid); 607 free(*pid); 608 free(*rid); 609 return (-1); 610 } 611 612 return (0); 613 } 614 615 /* 616 * Issue uscsi_inquiry and read_capacity commands to 617 * retrieve the disk's Vendor, Product, Revision and 618 * Capacity information. 619 */ 620 int 621 get_disk_info(int fd, struct efi_info *label, struct disk_info *disk_info) 622 { 623 (void) get_disk_capacity(fd, &label->capacity); 624 625 if (get_disk_inquiry_prop(disk_info->devfs_name, 626 &label->vendor, &label->product, &label->revision) != 0) { 627 if (get_disk_inquiry_devid(fd, &label->vendor, &label->product, 628 &label->revision) != 0) { 629 if (get_disk_inquiry_uscsi(fd, &label->vendor, 630 &label->product, &label->revision) != 0) { 631 label->vendor = strdup("Unknown"); 632 label->product = strdup("Unknown"); 633 label->revision = strdup("0001"); 634 if (label->vendor == NULL || 635 label->product == NULL || 636 label->revision == NULL) { 637 free(label->vendor); 638 free(label->product); 639 free(label->revision); 640 return (-1); 641 } 642 } 643 } 644 } 645 646 return (0); 647 } 648 649 int 650 read_efi_label(int fd, struct efi_info *label, struct disk_info *disk_info) 651 { 652 struct dk_gpt *vtoc64; 653 654 /* This could fail if there is no label already */ 655 if (efi_alloc_and_read(fd, &vtoc64) < 0) { 656 return (-1); 657 } 658 if (vtoc64_to_label(label, vtoc64) != 0) { 659 err_print("vtoc64_to_label failed\n"); 660 return (-1); 661 } 662 efi_free(vtoc64); 663 if (get_disk_info(fd, label, disk_info) != 0) { 664 return (-1); 665 } 666 return (0); 667 } 668 669 670 /* 671 * We've read a 64-bit label which has no geometry information. Use 672 * some heuristics to fake up a geometry that would match the disk in 673 * order to make the rest of format(1M) happy. 674 */ 675 static int 676 vtoc64_to_label(struct efi_info *label, struct dk_gpt *vtoc) 677 { 678 int i, nparts = 0; 679 struct dk_gpt *lmap; 680 681 (void) memset((char *)label, 0, sizeof (struct efi_info)); 682 683 /* XXX do a sanity check here for nparts */ 684 nparts = vtoc->efi_nparts; 685 lmap = (struct dk_gpt *) calloc(1, (sizeof (struct dk_part) * 686 nparts) + sizeof (struct dk_gpt)); 687 if (lmap == NULL) { 688 err_print("vtoc64_to_label: unable to allocate lmap\n"); 689 fullabort(); 690 } 691 label->e_parts = lmap; 692 693 /* 694 * Copy necessary portions 695 * XXX Maybe we can use memcpy() ?? 696 */ 697 lmap->efi_version = vtoc->efi_version; 698 lmap->efi_nparts = vtoc->efi_nparts; 699 lmap->efi_part_size = vtoc->efi_part_size; 700 lmap->efi_lbasize = vtoc->efi_lbasize; 701 lmap->efi_last_lba = vtoc->efi_last_lba; 702 lmap->efi_first_u_lba = vtoc->efi_first_u_lba; 703 lmap->efi_last_u_lba = vtoc->efi_last_u_lba; 704 lmap->efi_altern_lba = vtoc->efi_altern_lba; 705 lmap->efi_flags = vtoc->efi_flags; 706 (void) memcpy((uchar_t *)&lmap->efi_disk_uguid, 707 (uchar_t *)&vtoc->efi_disk_uguid, sizeof (struct uuid)); 708 709 for (i = 0; i < nparts; i++) { 710 lmap->efi_parts[i].p_tag = vtoc->efi_parts[i].p_tag; 711 lmap->efi_parts[i].p_flag = vtoc->efi_parts[i].p_flag; 712 lmap->efi_parts[i].p_start = vtoc->efi_parts[i].p_start; 713 lmap->efi_parts[i].p_size = vtoc->efi_parts[i].p_size; 714 (void) memcpy((uchar_t *)&lmap->efi_parts[i].p_uguid, 715 (uchar_t *)&vtoc->efi_parts[i].p_uguid, 716 sizeof (struct uuid)); 717 if (vtoc->efi_parts[i].p_tag == V_RESERVED) { 718 bcopy(vtoc->efi_parts[i].p_name, 719 lmap->efi_parts[i].p_name, LEN_DKL_VVOL); 720 } 721 } 722 return (0); 723 } 724 725 /* 726 * Convert vtoc/geom to label. 727 */ 728 static int 729 vtoc_to_label(struct dk_label *label, struct extvtoc *vtoc, 730 struct dk_geom *geom, struct dk_cinfo *cinfo) 731 { 732 #if defined(_SUNOS_VTOC_8) 733 struct dk_map32 *lmap; 734 #elif defined(_SUNOS_VTOC_16) 735 struct dkl_partition *lmap; 736 #else 737 #error No VTOC format defined. 738 #endif /* defined(_SUNOS_VTOC_8) */ 739 740 struct extpartition *vpart; 741 ulong_t nblks; 742 int i; 743 744 (void) memset((char *)label, 0, sizeof (struct dk_label)); 745 746 /* 747 * Sanity-check the vtoc 748 */ 749 if (vtoc->v_sanity != VTOC_SANE || 750 vtoc->v_nparts != V_NUMPAR) { 751 return (-1); 752 } 753 754 /* 755 * Sanity check of geometry 756 */ 757 if (geom->dkg_ncyl == 0 || geom->dkg_nhead == 0 || 758 geom->dkg_nsect == 0) { 759 return (-1); 760 } 761 762 label->dkl_magic = DKL_MAGIC; 763 764 /* 765 * Copy necessary portions of the geometry information 766 */ 767 label->dkl_rpm = geom->dkg_rpm; 768 label->dkl_pcyl = geom->dkg_pcyl; 769 label->dkl_apc = geom->dkg_apc; 770 label->dkl_intrlv = geom->dkg_intrlv; 771 label->dkl_ncyl = geom->dkg_ncyl; 772 label->dkl_acyl = geom->dkg_acyl; 773 774 #if defined(_SUNOS_VTOC_16) 775 label->dkl_bcyl = geom->dkg_bcyl; 776 #endif /* defined(_SUNOS_VTOC_16) */ 777 778 label->dkl_nhead = geom->dkg_nhead; 779 label->dkl_nsect = geom->dkg_nsect; 780 781 #if defined(_SUNOS_VTOC_8) 782 label->dkl_obs1 = geom->dkg_obs1; 783 label->dkl_obs2 = geom->dkg_obs2; 784 label->dkl_obs3 = geom->dkg_obs3; 785 #endif /* defined(_SUNOS_VTOC_8) */ 786 787 label->dkl_write_reinstruct = geom->dkg_write_reinstruct; 788 label->dkl_read_reinstruct = geom->dkg_read_reinstruct; 789 790 /* 791 * Copy vtoc structure fields into the disk label dk_vtoc 792 */ 793 label->dkl_vtoc.v_sanity = vtoc->v_sanity; 794 label->dkl_vtoc.v_nparts = vtoc->v_nparts; 795 label->dkl_vtoc.v_version = vtoc->v_version; 796 797 (void) memcpy(label->dkl_vtoc.v_volume, vtoc->v_volume, 798 LEN_DKL_VVOL); 799 for (i = 0; i < V_NUMPAR; i++) { 800 label->dkl_vtoc.v_part[i].p_tag = vtoc->v_part[i].p_tag; 801 label->dkl_vtoc.v_part[i].p_flag = vtoc->v_part[i].p_flag; 802 label->dkl_vtoc.v_timestamp[i] = vtoc->timestamp[i]; 803 } 804 805 for (i = 0; i < 10; i++) 806 label->dkl_vtoc.v_reserved[i] = vtoc->v_reserved[i]; 807 808 label->dkl_vtoc.v_bootinfo[0] = vtoc->v_bootinfo[0]; 809 label->dkl_vtoc.v_bootinfo[1] = vtoc->v_bootinfo[1]; 810 label->dkl_vtoc.v_bootinfo[2] = vtoc->v_bootinfo[2]; 811 812 (void) memcpy(label->dkl_asciilabel, vtoc->v_asciilabel, 813 LEN_DKL_ASCII); 814 815 /* 816 * Note the conversion from starting sector number 817 * to starting cylinder number. 818 * Return error if division results in a remainder. 819 * 820 * Note: don't check, if probing virtual disk in Xen 821 * for that virtual disk will use fabricated # of headers 822 * and sectors per track which may cause the capacity 823 * not multiple of # of blocks per cylinder 824 */ 825 #if defined(_SUNOS_VTOC_8) 826 lmap = label->dkl_map; 827 828 #elif defined(_SUNOS_VTOC_16) 829 lmap = label->dkl_vtoc.v_part; 830 #else 831 #error No VTOC format defined. 832 #endif /* defined(_SUNOS_VTOC_8) */ 833 834 vpart = vtoc->v_part; 835 836 nblks = label->dkl_nsect * label->dkl_nhead; 837 838 for (i = 0; i < NDKMAP; i++, lmap++, vpart++) { 839 if (cinfo->dki_ctype != DKC_VBD) { 840 if ((vpart->p_start % nblks) != 0 || 841 (vpart->p_size % nblks) != 0) { 842 return (-1); 843 } 844 } 845 #if defined(_SUNOS_VTOC_8) 846 lmap->dkl_cylno = (blkaddr32_t)(vpart->p_start / nblks); 847 lmap->dkl_nblk = (blkaddr32_t)vpart->p_size; 848 849 #elif defined(_SUNOS_VTOC_16) 850 lmap->p_start = (blkaddr32_t)vpart->p_start; 851 lmap->p_size = (blkaddr32_t)vpart->p_size; 852 #else 853 #error No VTOC format defined. 854 #endif /* defined(_SUNOS_VTOC_8) */ 855 } 856 857 /* 858 * Finally, make a checksum 859 */ 860 (void) checksum(label, CK_MAKESUM); 861 862 #ifdef DEBUG 863 if (option_msg && diag_msg) 864 dump_label(label); 865 #endif 866 return (0); 867 } 868 869 870 871 /* 872 * Extract a vtoc structure out of a valid label 873 */ 874 int 875 label_to_vtoc(struct extvtoc *vtoc, struct dk_label *label) 876 { 877 #if defined(_SUNOS_VTOC_8) 878 struct dk_map2 *lpart; 879 struct dk_map32 *lmap; 880 ulong_t nblks; 881 882 #elif defined(_SUNOS_VTOC_16) 883 struct dkl_partition *lpart; 884 #else 885 #error No VTOC format defined. 886 #endif /* defined(_SUNOS_VTOC_8) */ 887 888 struct extpartition *vpart; 889 int i; 890 891 (void) memset((char *)vtoc, 0, sizeof (struct extvtoc)); 892 893 switch (label->dkl_vtoc.v_version) { 894 case 0: 895 /* 896 * No valid vtoc information in the label. 897 * Construct default p_flags and p_tags. 898 */ 899 vpart = vtoc->v_part; 900 for (i = 0; i < V_NUMPAR; i++, vpart++) { 901 vpart->p_tag = default_vtoc_map[i].p_tag; 902 vpart->p_flag = default_vtoc_map[i].p_flag; 903 } 904 break; 905 906 case V_VERSION: 907 vpart = vtoc->v_part; 908 lpart = label->dkl_vtoc.v_part; 909 for (i = 0; i < V_NUMPAR; i++, vpart++, lpart++) { 910 vpart->p_tag = lpart->p_tag; 911 vpart->p_flag = lpart->p_flag; 912 913 #if defined(_SUNOS_VTOC_16) 914 vpart->p_start = (diskaddr_t)lpart->p_start; 915 vpart->p_size = (diskaddr_t)lpart->p_size; 916 #endif /* defined(_SUNOS_VTOC_16) */ 917 vtoc->timestamp[i] = label->dkl_vtoc.v_timestamp[i]; 918 } 919 (void) memcpy(vtoc->v_volume, label->dkl_vtoc.v_volume, 920 LEN_DKL_VVOL); 921 922 for (i = 0; i < 10; i++) 923 vtoc->v_reserved[i] = label->dkl_vtoc.v_reserved[i]; 924 925 vtoc->v_bootinfo[0] = label->dkl_vtoc.v_bootinfo[0]; 926 vtoc->v_bootinfo[1] = label->dkl_vtoc.v_bootinfo[1]; 927 vtoc->v_bootinfo[2] = label->dkl_vtoc.v_bootinfo[2]; 928 break; 929 930 default: 931 return (-1); 932 } 933 934 /* 935 * XXX - this looks wrong to me.... 936 * why are these values hardwired, rather than returned from 937 * the real disk label? 938 */ 939 vtoc->v_sanity = VTOC_SANE; 940 vtoc->v_version = V_VERSION; 941 vtoc->v_sectorsz = cur_blksz; 942 vtoc->v_nparts = V_NUMPAR; 943 944 (void) memcpy(vtoc->v_asciilabel, label->dkl_asciilabel, 945 LEN_DKL_ASCII); 946 947 #if defined(_SUNOS_VTOC_8) 948 /* 949 * Convert partitioning information. 950 * Note the conversion from starting cylinder number 951 * to starting sector number. 952 */ 953 lmap = label->dkl_map; 954 vpart = vtoc->v_part; 955 nblks = label->dkl_nsect * label->dkl_nhead; 956 for (i = 0; i < V_NUMPAR; i++, vpart++, lmap++) { 957 vpart->p_start = (diskaddr_t)(lmap->dkl_cylno * nblks); 958 vpart->p_size = (diskaddr_t)lmap->dkl_nblk; 959 } 960 #endif /* defined(_SUNOS_VTOC_8) */ 961 962 return (0); 963 } 964 965 /* 966 * Input: File descriptor 967 * Output: 1 if disk has an EFI label, 0 otherwise. 968 */ 969 970 int 971 is_efi_type(int fd) 972 { 973 struct extvtoc vtoc; 974 975 if (read_extvtoc(fd, &vtoc) == VT_ENOTSUP) { 976 /* assume the disk has EFI label */ 977 return (1); 978 } 979 return (0); 980 } 981 982 /* make sure the user specified something reasonable */ 983 void 984 err_check(struct dk_gpt *vtoc) 985 { 986 int resv_part = -1; 987 int i, j; 988 diskaddr_t istart, jstart, isize, jsize, endsect; 989 int overlap = 0; 990 uint_t reserved; 991 992 /* 993 * make sure no partitions overlap 994 */ 995 reserved = efi_reserved_sectors(vtoc); 996 for (i = 0; i < vtoc->efi_nparts; i++) { 997 /* It can't be unassigned and have an actual size */ 998 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) && 999 (vtoc->efi_parts[i].p_size != 0)) { 1000 (void) fprintf(stderr, 1001 "partition %d is \"unassigned\" but has a size of %llu\n", i, 1002 vtoc->efi_parts[i].p_size); 1003 } 1004 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) { 1005 continue; 1006 } 1007 if (vtoc->efi_parts[i].p_tag == V_RESERVED) { 1008 if (resv_part != -1) { 1009 (void) fprintf(stderr, 1010 "found duplicate reserved partition at %d\n", i); 1011 } 1012 resv_part = i; 1013 if (vtoc->efi_parts[i].p_size != reserved) 1014 (void) fprintf(stderr, 1015 "Warning: reserved partition size must be %u sectors\n", 1016 reserved); 1017 } 1018 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) || 1019 (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) { 1020 (void) fprintf(stderr, 1021 "Partition %d starts at %llu\n", 1022 i, 1023 vtoc->efi_parts[i].p_start); 1024 (void) fprintf(stderr, 1025 "It must be between %llu and %llu.\n", 1026 vtoc->efi_first_u_lba, 1027 vtoc->efi_last_u_lba); 1028 } 1029 if ((vtoc->efi_parts[i].p_start + 1030 vtoc->efi_parts[i].p_size < 1031 vtoc->efi_first_u_lba) || 1032 (vtoc->efi_parts[i].p_start + 1033 vtoc->efi_parts[i].p_size > 1034 vtoc->efi_last_u_lba + 1)) { 1035 (void) fprintf(stderr, 1036 "Partition %d ends at %llu\n", 1037 i, 1038 vtoc->efi_parts[i].p_start + 1039 vtoc->efi_parts[i].p_size); 1040 (void) fprintf(stderr, 1041 "It must be between %llu and %llu.\n", 1042 vtoc->efi_first_u_lba, 1043 vtoc->efi_last_u_lba); 1044 } 1045 1046 for (j = 0; j < vtoc->efi_nparts; j++) { 1047 isize = vtoc->efi_parts[i].p_size; 1048 jsize = vtoc->efi_parts[j].p_size; 1049 istart = vtoc->efi_parts[i].p_start; 1050 jstart = vtoc->efi_parts[j].p_start; 1051 if ((i != j) && (isize != 0) && (jsize != 0)) { 1052 endsect = jstart + jsize -1; 1053 if ((jstart <= istart) && 1054 (istart <= endsect)) { 1055 if (!overlap) { 1056 (void) fprintf(stderr, 1057 "label error: EFI Labels do not support overlapping partitions\n"); 1058 } 1059 (void) fprintf(stderr, 1060 "Partition %d overlaps partition %d.\n", i, j); 1061 overlap = 1; 1062 } 1063 } 1064 } 1065 } 1066 /* make sure there is a reserved partition */ 1067 if (resv_part == -1) { 1068 (void) fprintf(stderr, 1069 "no reserved partition found\n"); 1070 } 1071 } 1072 1073 #ifdef DEBUG 1074 static void 1075 dump_label(struct dk_label *label) 1076 { 1077 int i; 1078 1079 fmt_print("%s\n", label->dkl_asciilabel); 1080 1081 fmt_print("version: %d\n", label->dkl_vtoc.v_version); 1082 fmt_print("volume: "); 1083 for (i = 0; i < LEN_DKL_VVOL; i++) { 1084 if (label->dkl_vtoc.v_volume[i] == 0) 1085 break; 1086 fmt_print("%c", label->dkl_vtoc.v_volume[i]); 1087 } 1088 fmt_print("\n"); 1089 fmt_print("v_nparts: %d\n", label->dkl_vtoc.v_nparts); 1090 fmt_print("v_sanity: %lx\n", label->dkl_vtoc.v_sanity); 1091 1092 #if defined(_SUNOS_VTOC_8) 1093 fmt_print("rpm: %d\n", label->dkl_rpm); 1094 fmt_print("pcyl: %d\n", label->dkl_pcyl); 1095 fmt_print("apc: %d\n", label->dkl_apc); 1096 fmt_print("obs1: %d\n", label->dkl_obs1); 1097 fmt_print("obs2: %d\n", label->dkl_obs2); 1098 fmt_print("intrlv: %d\n", label->dkl_intrlv); 1099 fmt_print("ncyl: %d\n", label->dkl_ncyl); 1100 fmt_print("acyl: %d\n", label->dkl_acyl); 1101 fmt_print("nhead: %d\n", label->dkl_nhead); 1102 fmt_print("nsect: %d\n", label->dkl_nsect); 1103 fmt_print("obs3: %d\n", label->dkl_obs3); 1104 fmt_print("obs4: %d\n", label->dkl_obs4); 1105 1106 #elif defined(_SUNOS_VTOC_16) 1107 fmt_print("rpm: %d\n", label->dkl_rpm); 1108 fmt_print("pcyl: %d\n", label->dkl_pcyl); 1109 fmt_print("apc: %d\n", label->dkl_apc); 1110 fmt_print("intrlv: %d\n", label->dkl_intrlv); 1111 fmt_print("ncyl: %d\n", label->dkl_ncyl); 1112 fmt_print("acyl: %d\n", label->dkl_acyl); 1113 fmt_print("nhead: %d\n", label->dkl_nhead); 1114 fmt_print("nsect: %d\n", label->dkl_nsect); 1115 fmt_print("bcyl: %d\n", label->dkl_bcyl); 1116 fmt_print("skew: %d\n", label->dkl_skew); 1117 #else 1118 #error No VTOC format defined. 1119 #endif /* defined(_SUNOS_VTOC_8) */ 1120 fmt_print("magic: %0x\n", label->dkl_magic); 1121 fmt_print("cksum: %0x\n", label->dkl_cksum); 1122 1123 for (i = 0; i < NDKMAP; i++) { 1124 1125 #if defined(_SUNOS_VTOC_8) 1126 fmt_print("%c: cyl=%d, blocks=%d", i+'a', 1127 label->dkl_map[i].dkl_cylno, 1128 label->dkl_map[i].dkl_nblk); 1129 1130 #elif defined(_SUNOS_VTOC_16) 1131 fmt_print("%c: start=%u, blocks=%u", i+'a', 1132 label->dkl_vtoc.v_part[i].p_start, 1133 label->dkl_vtoc.v_part[i].p_size); 1134 #else 1135 #error No VTOC format defined. 1136 #endif /* defined(_SUNOS_VTOC_8) */ 1137 1138 fmt_print(", tag=%d, flag=%d", 1139 label->dkl_vtoc.v_part[i].p_tag, 1140 label->dkl_vtoc.v_part[i].p_flag); 1141 fmt_print("\n"); 1142 } 1143 1144 fmt_print("read_reinstruct: %d\n", label->dkl_read_reinstruct); 1145 fmt_print("write_reinstruct: %d\n", label->dkl_write_reinstruct); 1146 1147 fmt_print("bootinfo: "); 1148 for (i = 0; i < 3; i++) { 1149 fmt_print("0x%x ", label->dkl_vtoc.v_bootinfo[i]); 1150 } 1151 fmt_print("\n"); 1152 1153 fmt_print("reserved: "); 1154 for (i = 0; i < 10; i++) { 1155 if ((i % 4) == 3) 1156 fmt_print("\n"); 1157 fmt_print("0x%x ", label->dkl_vtoc.v_reserved[i]); 1158 } 1159 fmt_print("\n"); 1160 1161 fmt_print("timestamp:\n"); 1162 for (i = 0; i < NDKMAP; i++) { 1163 if ((i % 4) == 3) 1164 fmt_print("\n"); 1165 fmt_print("0x%x ", label->dkl_vtoc.v_timestamp[i]); 1166 } 1167 fmt_print("\n"); 1168 1169 fmt_print("pad:\n"); 1170 dump("", label->dkl_pad, LEN_DKL_PAD, HEX_ONLY); 1171 1172 fmt_print("\n\n"); 1173 } 1174 #endif /* DEBUG */ 1175