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