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