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