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