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