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