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 /*
  23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  * Copyright 2014 Toomas Soome <tsoome@me.com>
  26  */
  27 
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <errno.h>
  31 #include <strings.h>
  32 #include <unistd.h>
  33 #include <uuid/uuid.h>
  34 #include <libintl.h>
  35 #include <sys/types.h>
  36 #include <sys/dkio.h>
  37 #include <sys/vtoc.h>
  38 #include <sys/mhd.h>
  39 #include <sys/param.h>
  40 #include <sys/dktp/fdisk.h>
  41 #include <sys/efi_partition.h>
  42 #include <sys/byteorder.h>
  43 #include <sys/ddi.h>
  44 
  45 static struct uuid_to_ptag {
  46         struct uuid     uuid;
  47 } conversion_array[] = {
  48         { EFI_UNUSED },
  49         { EFI_BOOT },
  50         { EFI_ROOT },
  51         { EFI_SWAP },
  52         { EFI_USR },
  53         { EFI_BACKUP },
  54         { 0 },                  /* STAND is never used */
  55         { EFI_VAR },
  56         { EFI_HOME },
  57         { EFI_ALTSCTR },
  58         { 0 },                  /* CACHE is never used */
  59         { EFI_RESERVED },
  60         { EFI_SYSTEM },
  61         { EFI_LEGACY_MBR },
  62         { EFI_SYMC_PUB },
  63         { EFI_SYMC_CDS },
  64         { EFI_MSFT_RESV },
  65         { EFI_DELL_BASIC },
  66         { EFI_DELL_RAID },
  67         { EFI_DELL_SWAP },
  68         { EFI_DELL_LVM },
  69         { EFI_DELL_RESV },
  70         { EFI_AAPL_HFS },
  71         { EFI_AAPL_UFS },
  72         { EFI_BIOS_BOOT },
  73         { EFI_FREEBSD_BOOT },
  74         { EFI_FREEBSD_SWAP },
  75         { EFI_FREEBSD_UFS },
  76         { EFI_FREEBSD_VINUM },
  77         { EFI_FREEBSD_ZFS }
  78 };
  79 
  80 /*
  81  * Default vtoc information for non-SVr4 partitions
  82  */
  83 struct dk_map2  default_vtoc_map[NDKMAP] = {
  84         {       V_ROOT,         0       },              /* a - 0 */
  85         {       V_SWAP,         V_UNMNT },              /* b - 1 */
  86         {       V_BACKUP,       V_UNMNT },              /* c - 2 */
  87         {       V_UNASSIGNED,   0       },              /* d - 3 */
  88         {       V_UNASSIGNED,   0       },              /* e - 4 */
  89         {       V_UNASSIGNED,   0       },              /* f - 5 */
  90         {       V_USR,          0       },              /* g - 6 */
  91         {       V_UNASSIGNED,   0       },              /* h - 7 */
  92 
  93 #if defined(_SUNOS_VTOC_16)
  94 
  95 #if defined(i386) || defined(__amd64)
  96         {       V_BOOT,         V_UNMNT },              /* i - 8 */
  97         {       V_ALTSCTR,      0       },              /* j - 9 */
  98 
  99 #else
 100 #error No VTOC format defined.
 101 #endif                  /* defined(i386) */
 102 
 103         {       V_UNASSIGNED,   0       },              /* k - 10 */
 104         {       V_UNASSIGNED,   0       },              /* l - 11 */
 105         {       V_UNASSIGNED,   0       },              /* m - 12 */
 106         {       V_UNASSIGNED,   0       },              /* n - 13 */
 107         {       V_UNASSIGNED,   0       },              /* o - 14 */
 108         {       V_UNASSIGNED,   0       },              /* p - 15 */
 109 #endif                  /* defined(_SUNOS_VTOC_16) */
 110 };
 111 
 112 #ifdef DEBUG
 113 int efi_debug = 1;
 114 #else
 115 int efi_debug = 0;
 116 #endif
 117 
 118 extern unsigned int     efi_crc32(const unsigned char *, unsigned int);
 119 static int              efi_read(int, struct dk_gpt *);
 120 
 121 static int
 122 read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
 123 {
 124         struct dk_minfo         disk_info;
 125 
 126         if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
 127                 return (errno);
 128         *capacity = disk_info.dki_capacity;
 129         *lbsize = disk_info.dki_lbsize;
 130         return (0);
 131 }
 132 
 133 /*
 134  * the number of blocks the EFI label takes up (round up to nearest
 135  * block)
 136  */
 137 #define NBLOCKS(p, l)   (1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
 138                                 ((l) - 1)) / (l)))
 139 /* number of partitions -- limited by what we can malloc */
 140 #define MAX_PARTS       ((4294967295UL - sizeof (struct dk_gpt)) / \
 141                             sizeof (struct dk_part))
 142 
 143 int
 144 efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
 145 {
 146         diskaddr_t      capacity;
 147         uint_t          lbsize;
 148         uint_t          nblocks;
 149         size_t          length;
 150         struct dk_gpt   *vptr;
 151         struct uuid     uuid;
 152 
 153         if (read_disk_info(fd, &capacity, &lbsize) != 0) {
 154                 if (efi_debug)
 155                         (void) fprintf(stderr,
 156                             "couldn't read disk information\n");
 157                 return (-1);
 158         }
 159 
 160         nblocks = NBLOCKS(nparts, lbsize);
 161         if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
 162                 /* 16K plus one block for the GPT */
 163                 nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
 164         }
 165 
 166         if (nparts > MAX_PARTS) {
 167                 if (efi_debug) {
 168                         (void) fprintf(stderr,
 169                         "the maximum number of partitions supported is %lu\n",
 170                             MAX_PARTS);
 171                 }
 172                 return (-1);
 173         }
 174 
 175         length = sizeof (struct dk_gpt) +
 176             sizeof (struct dk_part) * (nparts - 1);
 177 
 178         if ((*vtoc = calloc(length, 1)) == NULL)
 179                 return (-1);
 180 
 181         vptr = *vtoc;
 182 
 183         vptr->efi_version = EFI_VERSION_CURRENT;
 184         vptr->efi_lbasize = lbsize;
 185         vptr->efi_nparts = nparts;
 186         /*
 187          * add one block here for the PMBR; on disks with a 512 byte
 188          * block size and 128 or fewer partitions, efi_first_u_lba
 189          * should work out to "34"
 190          */
 191         vptr->efi_first_u_lba = nblocks + 1;
 192         vptr->efi_last_lba = capacity - 1;
 193         vptr->efi_altern_lba = capacity -1;
 194         vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
 195 
 196         (void) uuid_generate((uchar_t *)&uuid);
 197         UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
 198         return (0);
 199 }
 200 
 201 /*
 202  * Read EFI - return partition number upon success.
 203  */
 204 int
 205 efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
 206 {
 207         int                     rval;
 208         uint32_t                nparts;
 209         int                     length;
 210 
 211         /* figure out the number of entries that would fit into 16K */
 212         nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
 213         length = (int) sizeof (struct dk_gpt) +
 214             (int) sizeof (struct dk_part) * (nparts - 1);
 215         if ((*vtoc = calloc(length, 1)) == NULL)
 216                 return (VT_ERROR);
 217 
 218         (*vtoc)->efi_nparts = nparts;
 219         rval = efi_read(fd, *vtoc);
 220 
 221         if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
 222                 void *tmp;
 223                 length = (int) sizeof (struct dk_gpt) +
 224                     (int) sizeof (struct dk_part) *
 225                     ((*vtoc)->efi_nparts - 1);
 226                 nparts = (*vtoc)->efi_nparts;
 227                 if ((tmp = realloc(*vtoc, length)) == NULL) {
 228                         free (*vtoc);
 229                         *vtoc = NULL;
 230                         return (VT_ERROR);
 231                 } else {
 232                         *vtoc = tmp;
 233                         rval = efi_read(fd, *vtoc);
 234                 }
 235         }
 236 
 237         if (rval < 0) {
 238                 if (efi_debug) {
 239                         (void) fprintf(stderr,
 240                             "read of EFI table failed, rval=%d\n", rval);
 241                 }
 242                 free (*vtoc);
 243                 *vtoc = NULL;
 244         }
 245 
 246         return (rval);
 247 }
 248 
 249 static int
 250 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
 251 {
 252         void *data = dk_ioc->dki_data;
 253         int error;
 254 
 255         dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
 256         error = ioctl(fd, cmd, (void *)dk_ioc);
 257         dk_ioc->dki_data = data;
 258 
 259         return (error);
 260 }
 261 
 262 static int
 263 check_label(int fd, dk_efi_t *dk_ioc)
 264 {
 265         efi_gpt_t               *efi;
 266         uint_t                  crc;
 267 
 268         if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
 269                 switch (errno) {
 270                 case EIO:
 271                         return (VT_EIO);
 272                 default:
 273                         return (VT_ERROR);
 274                 }
 275         }
 276         efi = dk_ioc->dki_data;
 277         if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
 278                 if (efi_debug)
 279                         (void) fprintf(stderr,
 280                             "Bad EFI signature: 0x%llx != 0x%llx\n",
 281                             (long long)efi->efi_gpt_Signature,
 282                             (long long)LE_64(EFI_SIGNATURE));
 283                 return (VT_EINVAL);
 284         }
 285 
 286         /*
 287          * check CRC of the header; the size of the header should
 288          * never be larger than one block
 289          */
 290         crc = efi->efi_gpt_HeaderCRC32;
 291         efi->efi_gpt_HeaderCRC32 = 0;
 292 
 293         if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
 294             crc != LE_32(efi_crc32((unsigned char *)efi,
 295             LE_32(efi->efi_gpt_HeaderSize)))) {
 296                 if (efi_debug)
 297                         (void) fprintf(stderr,
 298                             "Bad EFI CRC: 0x%x != 0x%x\n",
 299                             crc,
 300                             LE_32(efi_crc32((unsigned char *)efi,
 301                             sizeof (struct efi_gpt))));
 302                 return (VT_EINVAL);
 303         }
 304 
 305         return (0);
 306 }
 307 
 308 static int
 309 efi_read(int fd, struct dk_gpt *vtoc)
 310 {
 311         int                     i, j;
 312         int                     label_len;
 313         int                     rval = 0;
 314         int                     vdc_flag = 0;
 315         struct dk_minfo         disk_info;
 316         dk_efi_t                dk_ioc;
 317         efi_gpt_t               *efi;
 318         efi_gpe_t               *efi_parts;
 319         struct dk_cinfo         dki_info;
 320         uint32_t                user_length;
 321         boolean_t               legacy_label = B_FALSE;
 322 
 323         /*
 324          * get the partition number for this file descriptor.
 325          */
 326         if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
 327                 if (efi_debug) {
 328                         (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
 329                 }
 330                 switch (errno) {
 331                 case EIO:
 332                         return (VT_EIO);
 333                 case EINVAL:
 334                         return (VT_EINVAL);
 335                 default:
 336                         return (VT_ERROR);
 337                 }
 338         }
 339 
 340         if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
 341             (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
 342                 /*
 343                  * The controller and drive name "vdc" (virtual disk client)
 344                  * indicates a LDoms virtual disk.
 345                  */
 346                 vdc_flag++;
 347         }
 348 
 349         /* get the LBA size */
 350         if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
 351                 if (efi_debug) {
 352                         (void) fprintf(stderr,
 353                             "assuming LBA 512 bytes %d\n",
 354                             errno);
 355                 }
 356                 disk_info.dki_lbsize = DEV_BSIZE;
 357         }
 358         if (disk_info.dki_lbsize == 0) {
 359                 if (efi_debug) {
 360                         (void) fprintf(stderr,
 361                             "efi_read: assuming LBA 512 bytes\n");
 362                 }
 363                 disk_info.dki_lbsize = DEV_BSIZE;
 364         }
 365         /*
 366          * Read the EFI GPT to figure out how many partitions we need
 367          * to deal with.
 368          */
 369         dk_ioc.dki_lba = 1;
 370         if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
 371                 label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
 372         } else {
 373                 label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
 374                     disk_info.dki_lbsize;
 375                 if (label_len % disk_info.dki_lbsize) {
 376                         /* pad to physical sector size */
 377                         label_len += disk_info.dki_lbsize;
 378                         label_len &= ~(disk_info.dki_lbsize - 1);
 379                 }
 380         }
 381 
 382         if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
 383                 return (VT_ERROR);
 384 
 385         dk_ioc.dki_length = disk_info.dki_lbsize;
 386         user_length = vtoc->efi_nparts;
 387         efi = dk_ioc.dki_data;
 388         if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
 389                 /*
 390                  * No valid label here; try the alternate. Note that here
 391                  * we just read GPT header and save it into dk_ioc.data,
 392                  * Later, we will read GUID partition entry array if we
 393                  * can get valid GPT header.
 394                  */
 395 
 396                 /*
 397                  * This is a workaround for legacy systems. In the past, the
 398                  * last sector of SCSI disk was invisible on x86 platform. At
 399                  * that time, backup label was saved on the next to the last
 400                  * sector. It is possible for users to move a disk from previous
 401                  * solaris system to present system. Here, we attempt to search
 402                  * legacy backup EFI label first.
 403                  */
 404                 dk_ioc.dki_lba = disk_info.dki_capacity - 2;
 405                 dk_ioc.dki_length = disk_info.dki_lbsize;
 406                 rval = check_label(fd, &dk_ioc);
 407                 if (rval == VT_EINVAL) {
 408                         /*
 409                          * we didn't find legacy backup EFI label, try to
 410                          * search backup EFI label in the last block.
 411                          */
 412                         dk_ioc.dki_lba = disk_info.dki_capacity - 1;
 413                         dk_ioc.dki_length = disk_info.dki_lbsize;
 414                         rval = check_label(fd, &dk_ioc);
 415                         if (rval == 0) {
 416                                 legacy_label = B_TRUE;
 417                                 if (efi_debug)
 418                                         (void) fprintf(stderr,
 419                                             "efi_read: primary label corrupt; "
 420                                             "using EFI backup label located on"
 421                                             " the last block\n");
 422                         }
 423                 } else {
 424                         if ((efi_debug) && (rval == 0))
 425                                 (void) fprintf(stderr, "efi_read: primary label"
 426                                     " corrupt; using legacy EFI backup label "
 427                                     " located on the next to last block\n");
 428                 }
 429 
 430                 if (rval == 0) {
 431                         dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
 432                         vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
 433                         vtoc->efi_nparts =
 434                             LE_32(efi->efi_gpt_NumberOfPartitionEntries);
 435                         /*
 436                          * Partition tables are between backup GPT header
 437                          * table and ParitionEntryLBA (the starting LBA of
 438                          * the GUID partition entries array). Now that we
 439                          * already got valid GPT header and saved it in
 440                          * dk_ioc.dki_data, we try to get GUID partition
 441                          * entry array here.
 442                          */
 443                         /* LINTED */
 444                         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
 445                             + disk_info.dki_lbsize);
 446                         if (legacy_label)
 447                                 dk_ioc.dki_length = disk_info.dki_capacity - 1 -
 448                                     dk_ioc.dki_lba;
 449                         else
 450                                 dk_ioc.dki_length = disk_info.dki_capacity - 2 -
 451                                     dk_ioc.dki_lba;
 452                         dk_ioc.dki_length *= disk_info.dki_lbsize;
 453                         if (dk_ioc.dki_length >
 454                             ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
 455                                 rval = VT_EINVAL;
 456                         } else {
 457                                 /*
 458                                  * read GUID partition entry array
 459                                  */
 460                                 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
 461                         }
 462                 }
 463 
 464         } else if (rval == 0) {
 465 
 466                 dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
 467                 /* LINTED */
 468                 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
 469                     + disk_info.dki_lbsize);
 470                 dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
 471                 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
 472 
 473         } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
 474                 /*
 475                  * When the device is a LDoms virtual disk, the DKIOCGETEFI
 476                  * ioctl can fail with EINVAL if the virtual disk backend
 477                  * is a ZFS volume serviced by a domain running an old version
 478                  * of Solaris. This is because the DKIOCGETEFI ioctl was
 479                  * initially incorrectly implemented for a ZFS volume and it
 480                  * expected the GPT and GPE to be retrieved with a single ioctl.
 481                  * So we try to read the GPT and the GPE using that old style
 482                  * ioctl.
 483                  */
 484                 dk_ioc.dki_lba = 1;
 485                 dk_ioc.dki_length = label_len;
 486                 rval = check_label(fd, &dk_ioc);
 487         }
 488 
 489         if (rval < 0) {
 490                 free(efi);
 491                 return (rval);
 492         }
 493 
 494         /* LINTED -- always longlong aligned */
 495         efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
 496 
 497         /*
 498          * Assemble this into a "dk_gpt" struct for easier
 499          * digestibility by applications.
 500          */
 501         vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
 502         vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
 503         vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
 504         vtoc->efi_lbasize = disk_info.dki_lbsize;
 505         vtoc->efi_last_lba = disk_info.dki_capacity - 1;
 506         vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
 507         vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
 508         vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
 509         UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
 510 
 511         /*
 512          * If the array the user passed in is too small, set the length
 513          * to what it needs to be and return
 514          */
 515         if (user_length < vtoc->efi_nparts) {
 516                 return (VT_EINVAL);
 517         }
 518 
 519         for (i = 0; i < vtoc->efi_nparts; i++) {
 520 
 521                 UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
 522                     efi_parts[i].efi_gpe_PartitionTypeGUID);
 523 
 524                 for (j = 0;
 525                     j < sizeof (conversion_array)
 526                     / sizeof (struct uuid_to_ptag); j++) {
 527 
 528                         if (bcmp(&vtoc->efi_parts[i].p_guid,
 529                             &conversion_array[j].uuid,
 530                             sizeof (struct uuid)) == 0) {
 531                                 vtoc->efi_parts[i].p_tag = j;
 532                                 break;
 533                         }
 534                 }
 535                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
 536                         continue;
 537                 vtoc->efi_parts[i].p_flag =
 538                     LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
 539                 vtoc->efi_parts[i].p_start =
 540                     LE_64(efi_parts[i].efi_gpe_StartingLBA);
 541                 vtoc->efi_parts[i].p_size =
 542                     LE_64(efi_parts[i].efi_gpe_EndingLBA) -
 543                     vtoc->efi_parts[i].p_start + 1;
 544                 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
 545                         vtoc->efi_parts[i].p_name[j] =
 546                             (uchar_t)LE_16(
 547                             efi_parts[i].efi_gpe_PartitionName[j]);
 548                 }
 549 
 550                 UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
 551                     efi_parts[i].efi_gpe_UniquePartitionGUID);
 552         }
 553         free(efi);
 554 
 555         return (dki_info.dki_partition);
 556 }
 557 
 558 /* writes a "protective" MBR */
 559 static int
 560 write_pmbr(int fd, struct dk_gpt *vtoc)
 561 {
 562         dk_efi_t        dk_ioc;
 563         struct mboot    mb;
 564         uchar_t         *cp;
 565         diskaddr_t      size_in_lba;
 566         uchar_t         *buf;
 567         int             len;
 568 
 569         len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
 570         buf = calloc(len, 1);
 571 
 572         /*
 573          * Preserve any boot code and disk signature if the first block is
 574          * already an MBR.
 575          */
 576         dk_ioc.dki_lba = 0;
 577         dk_ioc.dki_length = len;
 578         /* LINTED -- always longlong aligned */
 579         dk_ioc.dki_data = (efi_gpt_t *)buf;
 580         if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
 581                 (void) memcpy(&mb, buf, sizeof (mb));
 582                 bzero(&mb, sizeof (mb));
 583                 mb.signature = LE_16(MBB_MAGIC);
 584         } else {
 585                 (void) memcpy(&mb, buf, sizeof (mb));
 586                 if (mb.signature != LE_16(MBB_MAGIC)) {
 587                         bzero(&mb, sizeof (mb));
 588                         mb.signature = LE_16(MBB_MAGIC);
 589                 }
 590         }
 591 
 592         bzero(&mb.parts, sizeof (mb.parts));
 593         cp = (uchar_t *)&mb.parts[0];
 594         /* bootable or not */
 595         *cp++ = 0;
 596         /* beginning CHS; 0xffffff if not representable */
 597         *cp++ = 0xff;
 598         *cp++ = 0xff;
 599         *cp++ = 0xff;
 600         /* OS type */
 601         *cp++ = EFI_PMBR;
 602         /* ending CHS; 0xffffff if not representable */
 603         *cp++ = 0xff;
 604         *cp++ = 0xff;
 605         *cp++ = 0xff;
 606         /* starting LBA: 1 (little endian format) by EFI definition */
 607         *cp++ = 0x01;
 608         *cp++ = 0x00;
 609         *cp++ = 0x00;
 610         *cp++ = 0x00;
 611         /* ending LBA: last block on the disk (little endian format) */
 612         size_in_lba = vtoc->efi_last_lba;
 613         if (size_in_lba < 0xffffffff) {
 614                 *cp++ = (size_in_lba & 0x000000ff);
 615                 *cp++ = (size_in_lba & 0x0000ff00) >> 8;
 616                 *cp++ = (size_in_lba & 0x00ff0000) >> 16;
 617                 *cp++ = (size_in_lba & 0xff000000) >> 24;
 618         } else {
 619                 *cp++ = 0xff;
 620                 *cp++ = 0xff;
 621                 *cp++ = 0xff;
 622                 *cp++ = 0xff;
 623         }
 624 
 625         (void) memcpy(buf, &mb, sizeof (mb));
 626         /* LINTED -- always longlong aligned */
 627         dk_ioc.dki_data = (efi_gpt_t *)buf;
 628         dk_ioc.dki_lba = 0;
 629         dk_ioc.dki_length = len;
 630         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
 631                 free(buf);
 632                 switch (errno) {
 633                 case EIO:
 634                         return (VT_EIO);
 635                 case EINVAL:
 636                         return (VT_EINVAL);
 637                 default:
 638                         return (VT_ERROR);
 639                 }
 640         }
 641         free(buf);
 642         return (0);
 643 }
 644 
 645 /* make sure the user specified something reasonable */
 646 static int
 647 check_input(struct dk_gpt *vtoc)
 648 {
 649         int                     resv_part = -1;
 650         int                     i, j;
 651         diskaddr_t              istart, jstart, isize, jsize, endsect;
 652 
 653         /*
 654          * Sanity-check the input (make sure no partitions overlap)
 655          */
 656         for (i = 0; i < vtoc->efi_nparts; i++) {
 657                 /* It can't be unassigned and have an actual size */
 658                 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
 659                     (vtoc->efi_parts[i].p_size != 0)) {
 660                         if (efi_debug) {
 661                                 (void) fprintf(stderr,
 662 "partition %d is \"unassigned\" but has a size of %llu",
 663                                     i,
 664                                     vtoc->efi_parts[i].p_size);
 665                         }
 666                         return (VT_EINVAL);
 667                 }
 668                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
 669                         if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
 670                                 continue;
 671                         /* we have encountered an unknown uuid */
 672                         vtoc->efi_parts[i].p_tag = 0xff;
 673                 }
 674                 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
 675                         if (resv_part != -1) {
 676                                 if (efi_debug) {
 677                                         (void) fprintf(stderr,
 678 "found duplicate reserved partition at %d\n",
 679                                             i);
 680                                 }
 681                                 return (VT_EINVAL);
 682                         }
 683                         resv_part = i;
 684                 }
 685                 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
 686                     (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
 687                         if (efi_debug) {
 688                                 (void) fprintf(stderr,
 689                                     "Partition %d starts at %llu.  ",
 690                                     i,
 691                                     vtoc->efi_parts[i].p_start);
 692                                 (void) fprintf(stderr,
 693                                     "It must be between %llu and %llu.\n",
 694                                     vtoc->efi_first_u_lba,
 695                                     vtoc->efi_last_u_lba);
 696                         }
 697                         return (VT_EINVAL);
 698                 }
 699                 if ((vtoc->efi_parts[i].p_start +
 700                     vtoc->efi_parts[i].p_size <
 701                     vtoc->efi_first_u_lba) ||
 702                     (vtoc->efi_parts[i].p_start +
 703                     vtoc->efi_parts[i].p_size >
 704                     vtoc->efi_last_u_lba + 1)) {
 705                         if (efi_debug) {
 706                                 (void) fprintf(stderr,
 707                                     "Partition %d ends at %llu.  ",
 708                                     i,
 709                                     vtoc->efi_parts[i].p_start +
 710                                     vtoc->efi_parts[i].p_size);
 711                                 (void) fprintf(stderr,
 712                                     "It must be between %llu and %llu.\n",
 713                                     vtoc->efi_first_u_lba,
 714                                     vtoc->efi_last_u_lba);
 715                         }
 716                         return (VT_EINVAL);
 717                 }
 718 
 719                 for (j = 0; j < vtoc->efi_nparts; j++) {
 720                         isize = vtoc->efi_parts[i].p_size;
 721                         jsize = vtoc->efi_parts[j].p_size;
 722                         istart = vtoc->efi_parts[i].p_start;
 723                         jstart = vtoc->efi_parts[j].p_start;
 724                         if ((i != j) && (isize != 0) && (jsize != 0)) {
 725                                 endsect = jstart + jsize -1;
 726                                 if ((jstart <= istart) &&
 727                                     (istart <= endsect)) {
 728                                         if (efi_debug) {
 729                                                 (void) fprintf(stderr,
 730 "Partition %d overlaps partition %d.",
 731                                                     i, j);
 732                                         }
 733                                         return (VT_EINVAL);
 734                                 }
 735                         }
 736                 }
 737         }
 738         /* just a warning for now */
 739         if ((resv_part == -1) && efi_debug) {
 740                 (void) fprintf(stderr,
 741                     "no reserved partition found\n");
 742         }
 743         return (0);
 744 }
 745 
 746 /*
 747  * add all the unallocated space to the current label
 748  */
 749 int
 750 efi_use_whole_disk(int fd)
 751 {
 752         struct dk_gpt           *efi_label;
 753         int                     rval;
 754         int                     i;
 755         uint_t                  phy_last_slice = 0;
 756         diskaddr_t              pl_start = 0;
 757         diskaddr_t              pl_size;
 758 
 759         rval = efi_alloc_and_read(fd, &efi_label);
 760         if (rval < 0) {
 761                 return (rval);
 762         }
 763 
 764         /* find the last physically non-zero partition */
 765         for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
 766                 if (pl_start < efi_label->efi_parts[i].p_start) {
 767                         pl_start = efi_label->efi_parts[i].p_start;
 768                         phy_last_slice = i;
 769                 }
 770         }
 771         pl_size = efi_label->efi_parts[phy_last_slice].p_size;
 772 
 773         /*
 774          * If alter_lba is 1, we are using the backup label.
 775          * Since we can locate the backup label by disk capacity,
 776          * there must be no unallocated space.
 777          */
 778         if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba
 779             >= efi_label->efi_last_lba)) {
 780                 if (efi_debug) {
 781                         (void) fprintf(stderr,
 782                             "efi_use_whole_disk: requested space not found\n");
 783                 }
 784                 efi_free(efi_label);
 785                 return (VT_ENOSPC);
 786         }
 787 
 788         /*
 789          * If there is space between the last physically non-zero partition
 790          * and the reserved partition, just add the unallocated space to this
 791          * area. Otherwise, the unallocated space is added to the last
 792          * physically non-zero partition.
 793          */
 794         if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
 795             EFI_MIN_RESV_SIZE) {
 796                 efi_label->efi_parts[phy_last_slice].p_size +=
 797                     efi_label->efi_last_lba - efi_label->efi_altern_lba;
 798         }
 799 
 800         /*
 801          * Move the reserved partition. There is currently no data in
 802          * here except fabricated devids (which get generated via
 803          * efi_write()). So there is no need to copy data.
 804          */
 805         efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
 806             efi_label->efi_last_lba - efi_label->efi_altern_lba;
 807         efi_label->efi_last_u_lba += efi_label->efi_last_lba
 808             - efi_label->efi_altern_lba;
 809 
 810         rval = efi_write(fd, efi_label);
 811         if (rval < 0) {
 812                 if (efi_debug) {
 813                         (void) fprintf(stderr,
 814                             "efi_use_whole_disk:fail to write label, rval=%d\n",
 815                             rval);
 816                 }
 817                 efi_free(efi_label);
 818                 return (rval);
 819         }
 820 
 821         efi_free(efi_label);
 822         return (0);
 823 }
 824 
 825 
 826 /*
 827  * write EFI label and backup label
 828  */
 829 int
 830 efi_write(int fd, struct dk_gpt *vtoc)
 831 {
 832         dk_efi_t                dk_ioc;
 833         efi_gpt_t               *efi;
 834         efi_gpe_t               *efi_parts;
 835         int                     i, j;
 836         struct dk_cinfo         dki_info;
 837         int                     nblocks;
 838         diskaddr_t              lba_backup_gpt_hdr;
 839 
 840         if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
 841                 if (efi_debug)
 842                         (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
 843                 switch (errno) {
 844                 case EIO:
 845                         return (VT_EIO);
 846                 case EINVAL:
 847                         return (VT_EINVAL);
 848                 default:
 849                         return (VT_ERROR);
 850                 }
 851         }
 852 
 853         if (check_input(vtoc))
 854                 return (VT_EINVAL);
 855 
 856         dk_ioc.dki_lba = 1;
 857         if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
 858                 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
 859         } else {
 860                 dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
 861                     vtoc->efi_lbasize) *
 862                     vtoc->efi_lbasize;
 863         }
 864 
 865         /*
 866          * the number of blocks occupied by GUID partition entry array
 867          */
 868         nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
 869 
 870         /*
 871          * Backup GPT header is located on the block after GUID
 872          * partition entry array. Here, we calculate the address
 873          * for backup GPT header.
 874          */
 875         lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
 876         if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL)
 877                 return (VT_ERROR);
 878 
 879         efi = dk_ioc.dki_data;
 880 
 881         /* stuff user's input into EFI struct */
 882         efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
 883         efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
 884         efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
 885         efi->efi_gpt_Reserved1 = 0;
 886         efi->efi_gpt_MyLBA = LE_64(1ULL);
 887         efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
 888         efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
 889         efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
 890         efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
 891         efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
 892         efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
 893         UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
 894 
 895         /* LINTED -- always longlong aligned */
 896         efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
 897 
 898         for (i = 0; i < vtoc->efi_nparts; i++) {
 899                 for (j = 0;
 900                     j < sizeof (conversion_array) /
 901                     sizeof (struct uuid_to_ptag); j++) {
 902 
 903                         if (vtoc->efi_parts[i].p_tag == j) {
 904                                 UUID_LE_CONVERT(
 905                                     efi_parts[i].efi_gpe_PartitionTypeGUID,
 906                                     conversion_array[j].uuid);
 907                                 break;
 908                         }
 909                 }
 910 
 911                 if (j == sizeof (conversion_array) /
 912                     sizeof (struct uuid_to_ptag)) {
 913                         /*
 914                          * If we didn't have a matching uuid match, bail here.
 915                          * Don't write a label with unknown uuid.
 916                          */
 917                         if (efi_debug) {
 918                                 (void) fprintf(stderr,
 919                                     "Unknown uuid for p_tag %d\n",
 920                                     vtoc->efi_parts[i].p_tag);
 921                         }
 922                         return (VT_EINVAL);
 923                 }
 924 
 925                 efi_parts[i].efi_gpe_StartingLBA =
 926                     LE_64(vtoc->efi_parts[i].p_start);
 927                 efi_parts[i].efi_gpe_EndingLBA =
 928                     LE_64(vtoc->efi_parts[i].p_start +
 929                     vtoc->efi_parts[i].p_size - 1);
 930                 efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
 931                     LE_16(vtoc->efi_parts[i].p_flag);
 932                 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
 933                         efi_parts[i].efi_gpe_PartitionName[j] =
 934                             LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
 935                 }
 936                 if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
 937                     uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
 938                         (void) uuid_generate((uchar_t *)
 939                             &vtoc->efi_parts[i].p_uguid);
 940                 }
 941                 bcopy(&vtoc->efi_parts[i].p_uguid,
 942                     &efi_parts[i].efi_gpe_UniquePartitionGUID,
 943                     sizeof (uuid_t));
 944         }
 945         efi->efi_gpt_PartitionEntryArrayCRC32 =
 946             LE_32(efi_crc32((unsigned char *)efi_parts,
 947             vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
 948         efi->efi_gpt_HeaderCRC32 =
 949             LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
 950 
 951         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
 952                 free(dk_ioc.dki_data);
 953                 switch (errno) {
 954                 case EIO:
 955                         return (VT_EIO);
 956                 case EINVAL:
 957                         return (VT_EINVAL);
 958                 default:
 959                         return (VT_ERROR);
 960                 }
 961         }
 962 
 963         /* write backup partition array */
 964         dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
 965         dk_ioc.dki_length -= vtoc->efi_lbasize;
 966         /* LINTED */
 967         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
 968             vtoc->efi_lbasize);
 969 
 970         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
 971                 /*
 972                  * we wrote the primary label okay, so don't fail
 973                  */
 974                 if (efi_debug) {
 975                         (void) fprintf(stderr,
 976                             "write of backup partitions to block %llu "
 977                             "failed, errno %d\n",
 978                             vtoc->efi_last_u_lba + 1,
 979                             errno);
 980                 }
 981         }
 982         /*
 983          * now swap MyLBA and AlternateLBA fields and write backup
 984          * partition table header
 985          */
 986         dk_ioc.dki_lba = lba_backup_gpt_hdr;
 987         dk_ioc.dki_length = vtoc->efi_lbasize;
 988         /* LINTED */
 989         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
 990             vtoc->efi_lbasize);
 991         efi->efi_gpt_AlternateLBA = LE_64(1ULL);
 992         efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
 993         efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
 994         efi->efi_gpt_HeaderCRC32 = 0;
 995         efi->efi_gpt_HeaderCRC32 =
 996             LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
 997             sizeof (struct efi_gpt)));
 998 
 999         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1000                 if (efi_debug) {
1001                         (void) fprintf(stderr,
1002                             "write of backup header to block %llu failed, "
1003                             "errno %d\n",
1004                             lba_backup_gpt_hdr,
1005                             errno);
1006                 }
1007         }
1008         /* write the PMBR */
1009         (void) write_pmbr(fd, vtoc);
1010         free(dk_ioc.dki_data);
1011         return (0);
1012 }
1013 
1014 void
1015 efi_free(struct dk_gpt *ptr)
1016 {
1017         free(ptr);
1018 }
1019 
1020 /*
1021  * Input: File descriptor
1022  * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
1023  * Otherwise 0.
1024  */
1025 int
1026 efi_type(int fd)
1027 {
1028         struct vtoc vtoc;
1029         struct extvtoc extvtoc;
1030 
1031         if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) {
1032                 if (errno == ENOTSUP)
1033                         return (1);
1034                 else if (errno == ENOTTY) {
1035                         if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1)
1036                                 if (errno == ENOTSUP)
1037                                         return (1);
1038                 }
1039         }
1040         return (0);
1041 }
1042 
1043 void
1044 efi_err_check(struct dk_gpt *vtoc)
1045 {
1046         int                     resv_part = -1;
1047         int                     i, j;
1048         diskaddr_t              istart, jstart, isize, jsize, endsect;
1049         int                     overlap = 0;
1050 
1051         /*
1052          * make sure no partitions overlap
1053          */
1054         for (i = 0; i < vtoc->efi_nparts; i++) {
1055                 /* It can't be unassigned and have an actual size */
1056                 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
1057                     (vtoc->efi_parts[i].p_size != 0)) {
1058                         (void) fprintf(stderr,
1059                             "partition %d is \"unassigned\" but has a size "
1060                             "of %llu\n", i, vtoc->efi_parts[i].p_size);
1061                 }
1062                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
1063                         continue;
1064                 }
1065                 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
1066                         if (resv_part != -1) {
1067                                 (void) fprintf(stderr,
1068                                     "found duplicate reserved partition at "
1069                                     "%d\n", i);
1070                         }
1071                         resv_part = i;
1072                         if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
1073                                 (void) fprintf(stderr,
1074                                     "Warning: reserved partition size must "
1075                                     "be %d sectors\n", EFI_MIN_RESV_SIZE);
1076                 }
1077                 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
1078                     (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
1079                         (void) fprintf(stderr,
1080                             "Partition %d starts at %llu\n",
1081                             i,
1082                             vtoc->efi_parts[i].p_start);
1083                         (void) fprintf(stderr,
1084                             "It must be between %llu and %llu.\n",
1085                             vtoc->efi_first_u_lba,
1086                             vtoc->efi_last_u_lba);
1087                 }
1088                 if ((vtoc->efi_parts[i].p_start +
1089                     vtoc->efi_parts[i].p_size <
1090                     vtoc->efi_first_u_lba) ||
1091                     (vtoc->efi_parts[i].p_start +
1092                     vtoc->efi_parts[i].p_size >
1093                     vtoc->efi_last_u_lba + 1)) {
1094                         (void) fprintf(stderr,
1095                             "Partition %d ends at %llu\n",
1096                             i,
1097                             vtoc->efi_parts[i].p_start +
1098                             vtoc->efi_parts[i].p_size);
1099                         (void) fprintf(stderr,
1100                             "It must be between %llu and %llu.\n",
1101                             vtoc->efi_first_u_lba,
1102                             vtoc->efi_last_u_lba);
1103                 }
1104 
1105                 for (j = 0; j < vtoc->efi_nparts; j++) {
1106                         isize = vtoc->efi_parts[i].p_size;
1107                         jsize = vtoc->efi_parts[j].p_size;
1108                         istart = vtoc->efi_parts[i].p_start;
1109                         jstart = vtoc->efi_parts[j].p_start;
1110                         if ((i != j) && (isize != 0) && (jsize != 0)) {
1111                                 endsect = jstart + jsize -1;
1112                                 if ((jstart <= istart) &&
1113                                     (istart <= endsect)) {
1114                                         if (!overlap) {
1115                                         (void) fprintf(stderr,
1116                                             "label error: EFI Labels do not "
1117                                             "support overlapping partitions\n");
1118                                         }
1119                                         (void) fprintf(stderr,
1120                                             "Partition %d overlaps partition "
1121                                             "%d.\n", i, j);
1122                                         overlap = 1;
1123                                 }
1124                         }
1125                 }
1126         }
1127         /* make sure there is a reserved partition */
1128         if (resv_part == -1) {
1129                 (void) fprintf(stderr,
1130                     "no reserved partition found\n");
1131         }
1132 }
1133 
1134 /*
1135  * We need to get information necessary to construct a *new* efi
1136  * label type
1137  */
1138 int
1139 efi_auto_sense(int fd, struct dk_gpt **vtoc)
1140 {
1141 
1142         int     i;
1143 
1144         /*
1145          * Now build the default partition table
1146          */
1147         if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
1148                 if (efi_debug) {
1149                         (void) fprintf(stderr, "efi_alloc_and_init failed.\n");
1150                 }
1151                 return (-1);
1152         }
1153 
1154         for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
1155                 (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
1156                 (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
1157                 (*vtoc)->efi_parts[i].p_start = 0;
1158                 (*vtoc)->efi_parts[i].p_size = 0;
1159         }
1160         /*
1161          * Make constants first
1162          * and variable partitions later
1163          */
1164 
1165         /* root partition - s0 128 MB */
1166         (*vtoc)->efi_parts[0].p_start = 34;
1167         (*vtoc)->efi_parts[0].p_size = 262144;
1168 
1169         /* partition - s1  128 MB */
1170         (*vtoc)->efi_parts[1].p_start = 262178;
1171         (*vtoc)->efi_parts[1].p_size = 262144;
1172 
1173         /* partition -s2 is NOT the Backup disk */
1174         (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
1175 
1176         /* partition -s6 /usr partition - HOG */
1177         (*vtoc)->efi_parts[6].p_start = 524322;
1178         (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
1179             - (1024 * 16);
1180 
1181         /* efi reserved partition - s9 16K */
1182         (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
1183         (*vtoc)->efi_parts[8].p_size = (1024 * 16);
1184         (*vtoc)->efi_parts[8].p_tag = V_RESERVED;
1185         return (0);
1186 }