10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52285Scg149915 * Common Development and Distribution License (the "License").
62285Scg149915 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
217563SPrasad.Singamsetty@Sun.COM
220Sstevel@tonic-gate /*
23*13027SSharath.Srinivasan@Sun.COM * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <errno.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <uuid/uuid.h>
320Sstevel@tonic-gate #include <libintl.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/dkio.h>
350Sstevel@tonic-gate #include <sys/vtoc.h>
360Sstevel@tonic-gate #include <sys/mhd.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
390Sstevel@tonic-gate #include <sys/efi_partition.h>
400Sstevel@tonic-gate #include <sys/byteorder.h>
410Sstevel@tonic-gate #include <sys/ddi.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate static struct uuid_to_ptag {
440Sstevel@tonic-gate struct uuid uuid;
450Sstevel@tonic-gate } conversion_array[] = {
460Sstevel@tonic-gate { EFI_UNUSED },
470Sstevel@tonic-gate { EFI_BOOT },
480Sstevel@tonic-gate { EFI_ROOT },
490Sstevel@tonic-gate { EFI_SWAP },
500Sstevel@tonic-gate { EFI_USR },
510Sstevel@tonic-gate { EFI_BACKUP },
520Sstevel@tonic-gate { 0 }, /* STAND is never used */
530Sstevel@tonic-gate { EFI_VAR },
540Sstevel@tonic-gate { EFI_HOME },
550Sstevel@tonic-gate { EFI_ALTSCTR },
560Sstevel@tonic-gate { 0 }, /* CACHE (cachefs) is never used */
570Sstevel@tonic-gate { EFI_RESERVED },
580Sstevel@tonic-gate { EFI_SYSTEM },
590Sstevel@tonic-gate { EFI_LEGACY_MBR },
60*13027SSharath.Srinivasan@Sun.COM { EFI_SYMC_PUB },
61*13027SSharath.Srinivasan@Sun.COM { EFI_SYMC_CDS },
620Sstevel@tonic-gate { EFI_MSFT_RESV },
630Sstevel@tonic-gate { EFI_DELL_BASIC },
640Sstevel@tonic-gate { EFI_DELL_RAID },
650Sstevel@tonic-gate { EFI_DELL_SWAP },
660Sstevel@tonic-gate { EFI_DELL_LVM },
672866Sszhou { EFI_DELL_RESV },
682866Sszhou { EFI_AAPL_HFS },
692866Sszhou { EFI_AAPL_UFS }
700Sstevel@tonic-gate };
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * Default vtoc information for non-SVr4 partitions
740Sstevel@tonic-gate */
750Sstevel@tonic-gate struct dk_map2 default_vtoc_map[NDKMAP] = {
760Sstevel@tonic-gate { V_ROOT, 0 }, /* a - 0 */
770Sstevel@tonic-gate { V_SWAP, V_UNMNT }, /* b - 1 */
780Sstevel@tonic-gate { V_BACKUP, V_UNMNT }, /* c - 2 */
790Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* d - 3 */
800Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* e - 4 */
810Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* f - 5 */
820Sstevel@tonic-gate { V_USR, 0 }, /* g - 6 */
830Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* h - 7 */
840Sstevel@tonic-gate
850Sstevel@tonic-gate #if defined(_SUNOS_VTOC_16)
860Sstevel@tonic-gate
870Sstevel@tonic-gate #if defined(i386) || defined(__amd64)
880Sstevel@tonic-gate { V_BOOT, V_UNMNT }, /* i - 8 */
890Sstevel@tonic-gate { V_ALTSCTR, 0 }, /* j - 9 */
900Sstevel@tonic-gate
910Sstevel@tonic-gate #else
920Sstevel@tonic-gate #error No VTOC format defined.
930Sstevel@tonic-gate #endif /* defined(i386) */
940Sstevel@tonic-gate
950Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* k - 10 */
960Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* l - 11 */
970Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* m - 12 */
980Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* n - 13 */
990Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* o - 14 */
1000Sstevel@tonic-gate { V_UNASSIGNED, 0 }, /* p - 15 */
1010Sstevel@tonic-gate #endif /* defined(_SUNOS_VTOC_16) */
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate #ifdef DEBUG
1050Sstevel@tonic-gate int efi_debug = 1;
1060Sstevel@tonic-gate #else
1070Sstevel@tonic-gate int efi_debug = 0;
1080Sstevel@tonic-gate #endif
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate extern unsigned int efi_crc32(const unsigned char *, unsigned int);
1110Sstevel@tonic-gate static int efi_read(int, struct dk_gpt *);
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate static int
read_disk_info(int fd,diskaddr_t * capacity,uint_t * lbsize)1140Sstevel@tonic-gate read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate struct dk_minfo disk_info;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
1190Sstevel@tonic-gate return (errno);
1200Sstevel@tonic-gate *capacity = disk_info.dki_capacity;
1210Sstevel@tonic-gate *lbsize = disk_info.dki_lbsize;
1220Sstevel@tonic-gate return (0);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate * the number of blocks the EFI label takes up (round up to nearest
1270Sstevel@tonic-gate * block)
1280Sstevel@tonic-gate */
1290Sstevel@tonic-gate #define NBLOCKS(p, l) (1 + ((((p) * (int)sizeof (efi_gpe_t)) + \
1300Sstevel@tonic-gate ((l) - 1)) / (l)))
1310Sstevel@tonic-gate /* number of partitions -- limited by what we can malloc */
1320Sstevel@tonic-gate #define MAX_PARTS ((4294967295UL - sizeof (struct dk_gpt)) / \
1330Sstevel@tonic-gate sizeof (struct dk_part))
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate int
efi_alloc_and_init(int fd,uint32_t nparts,struct dk_gpt ** vtoc)1360Sstevel@tonic-gate efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate diskaddr_t capacity;
1390Sstevel@tonic-gate uint_t lbsize;
1400Sstevel@tonic-gate uint_t nblocks;
1410Sstevel@tonic-gate size_t length;
1420Sstevel@tonic-gate struct dk_gpt *vptr;
1430Sstevel@tonic-gate struct uuid uuid;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate if (read_disk_info(fd, &capacity, &lbsize) != 0) {
1460Sstevel@tonic-gate if (efi_debug)
1470Sstevel@tonic-gate (void) fprintf(stderr,
1480Sstevel@tonic-gate "couldn't read disk information\n");
1490Sstevel@tonic-gate return (-1);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate nblocks = NBLOCKS(nparts, lbsize);
1530Sstevel@tonic-gate if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
1540Sstevel@tonic-gate /* 16K plus one block for the GPT */
1550Sstevel@tonic-gate nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate if (nparts > MAX_PARTS) {
1590Sstevel@tonic-gate if (efi_debug) {
1600Sstevel@tonic-gate (void) fprintf(stderr,
1610Sstevel@tonic-gate "the maximum number of partitions supported is %lu\n",
1620Sstevel@tonic-gate MAX_PARTS);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate return (-1);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate length = sizeof (struct dk_gpt) +
1680Sstevel@tonic-gate sizeof (struct dk_part) * (nparts - 1);
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate if ((*vtoc = calloc(length, 1)) == NULL)
1710Sstevel@tonic-gate return (-1);
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate vptr = *vtoc;
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate vptr->efi_version = EFI_VERSION_CURRENT;
1760Sstevel@tonic-gate vptr->efi_lbasize = lbsize;
1770Sstevel@tonic-gate vptr->efi_nparts = nparts;
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate * add one block here for the PMBR; on disks with a 512 byte
1800Sstevel@tonic-gate * block size and 128 or fewer partitions, efi_first_u_lba
1810Sstevel@tonic-gate * should work out to "34"
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate vptr->efi_first_u_lba = nblocks + 1;
1840Sstevel@tonic-gate vptr->efi_last_lba = capacity - 1;
1856590Syl194034 vptr->efi_altern_lba = capacity -1;
1860Sstevel@tonic-gate vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
1879889SLarry.Liu@Sun.COM
1880Sstevel@tonic-gate (void) uuid_generate((uchar_t *)&uuid);
1890Sstevel@tonic-gate UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
1900Sstevel@tonic-gate return (0);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate * Read EFI - return partition number upon success.
1950Sstevel@tonic-gate */
1960Sstevel@tonic-gate int
efi_alloc_and_read(int fd,struct dk_gpt ** vtoc)1970Sstevel@tonic-gate efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate int rval;
2000Sstevel@tonic-gate uint32_t nparts;
2010Sstevel@tonic-gate int length;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate /* figure out the number of entries that would fit into 16K */
2040Sstevel@tonic-gate nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
2050Sstevel@tonic-gate length = (int) sizeof (struct dk_gpt) +
2066590Syl194034 (int) sizeof (struct dk_part) * (nparts - 1);
2070Sstevel@tonic-gate if ((*vtoc = calloc(length, 1)) == NULL)
2080Sstevel@tonic-gate return (VT_ERROR);
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate (*vtoc)->efi_nparts = nparts;
2110Sstevel@tonic-gate rval = efi_read(fd, *vtoc);
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
2140Sstevel@tonic-gate void *tmp;
2150Sstevel@tonic-gate length = (int) sizeof (struct dk_gpt) +
2166590Syl194034 (int) sizeof (struct dk_part) *
2176590Syl194034 ((*vtoc)->efi_nparts - 1);
2180Sstevel@tonic-gate nparts = (*vtoc)->efi_nparts;
2190Sstevel@tonic-gate if ((tmp = realloc(*vtoc, length)) == NULL) {
2200Sstevel@tonic-gate free (*vtoc);
2210Sstevel@tonic-gate *vtoc = NULL;
2220Sstevel@tonic-gate return (VT_ERROR);
2230Sstevel@tonic-gate } else {
2240Sstevel@tonic-gate *vtoc = tmp;
2250Sstevel@tonic-gate rval = efi_read(fd, *vtoc);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate if (rval < 0) {
2300Sstevel@tonic-gate if (efi_debug) {
2310Sstevel@tonic-gate (void) fprintf(stderr,
2320Sstevel@tonic-gate "read of EFI table failed, rval=%d\n", rval);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate free (*vtoc);
2350Sstevel@tonic-gate *vtoc = NULL;
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate return (rval);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate static int
efi_ioctl(int fd,int cmd,dk_efi_t * dk_ioc)2420Sstevel@tonic-gate efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate void *data = dk_ioc->dki_data;
2450Sstevel@tonic-gate int error;
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
2480Sstevel@tonic-gate error = ioctl(fd, cmd, (void *)dk_ioc);
2490Sstevel@tonic-gate dk_ioc->dki_data = data;
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate return (error);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate static int
check_label(int fd,dk_efi_t * dk_ioc)2550Sstevel@tonic-gate check_label(int fd, dk_efi_t *dk_ioc)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate efi_gpt_t *efi;
2580Sstevel@tonic-gate uint_t crc;
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
2610Sstevel@tonic-gate switch (errno) {
2620Sstevel@tonic-gate case EIO:
2630Sstevel@tonic-gate return (VT_EIO);
2640Sstevel@tonic-gate default:
2650Sstevel@tonic-gate return (VT_ERROR);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate efi = dk_ioc->dki_data;
2690Sstevel@tonic-gate if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
2700Sstevel@tonic-gate if (efi_debug)
2710Sstevel@tonic-gate (void) fprintf(stderr,
2720Sstevel@tonic-gate "Bad EFI signature: 0x%llx != 0x%llx\n",
2730Sstevel@tonic-gate (long long)efi->efi_gpt_Signature,
2740Sstevel@tonic-gate (long long)LE_64(EFI_SIGNATURE));
2750Sstevel@tonic-gate return (VT_EINVAL);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * check CRC of the header; the size of the header should
2800Sstevel@tonic-gate * never be larger than one block
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate crc = efi->efi_gpt_HeaderCRC32;
2830Sstevel@tonic-gate efi->efi_gpt_HeaderCRC32 = 0;
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
2860Sstevel@tonic-gate crc != LE_32(efi_crc32((unsigned char *)efi,
2870Sstevel@tonic-gate LE_32(efi->efi_gpt_HeaderSize)))) {
2880Sstevel@tonic-gate if (efi_debug)
2890Sstevel@tonic-gate (void) fprintf(stderr,
2906590Syl194034 "Bad EFI CRC: 0x%x != 0x%x\n",
2916590Syl194034 crc,
2926590Syl194034 LE_32(efi_crc32((unsigned char *)efi,
2936590Syl194034 sizeof (struct efi_gpt))));
2940Sstevel@tonic-gate return (VT_EINVAL);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate return (0);
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate static int
efi_read(int fd,struct dk_gpt * vtoc)3010Sstevel@tonic-gate efi_read(int fd, struct dk_gpt *vtoc)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate int i, j;
3040Sstevel@tonic-gate int label_len;
3050Sstevel@tonic-gate int rval = 0;
3060Sstevel@tonic-gate int md_flag = 0;
3078528SAlexandre.Chartre@Sun.COM int vdc_flag = 0;
3080Sstevel@tonic-gate struct dk_minfo disk_info;
3090Sstevel@tonic-gate dk_efi_t dk_ioc;
3100Sstevel@tonic-gate efi_gpt_t *efi;
3110Sstevel@tonic-gate efi_gpe_t *efi_parts;
3120Sstevel@tonic-gate struct dk_cinfo dki_info;
3130Sstevel@tonic-gate uint32_t user_length;
3143083Scg149915 boolean_t legacy_label = B_FALSE;
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * get the partition number for this file descriptor.
3180Sstevel@tonic-gate */
3190Sstevel@tonic-gate if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
3206590Syl194034 if (efi_debug) {
3216590Syl194034 (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
3226590Syl194034 }
3230Sstevel@tonic-gate switch (errno) {
3240Sstevel@tonic-gate case EIO:
3250Sstevel@tonic-gate return (VT_EIO);
3260Sstevel@tonic-gate case EINVAL:
3270Sstevel@tonic-gate return (VT_EINVAL);
3280Sstevel@tonic-gate default:
3290Sstevel@tonic-gate return (VT_ERROR);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
3330Sstevel@tonic-gate (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
3340Sstevel@tonic-gate md_flag++;
3358528SAlexandre.Chartre@Sun.COM } else if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
3368528SAlexandre.Chartre@Sun.COM (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
3378528SAlexandre.Chartre@Sun.COM /*
3388528SAlexandre.Chartre@Sun.COM * The controller and drive name "vdc" (virtual disk client)
3398528SAlexandre.Chartre@Sun.COM * indicates a LDoms virtual disk.
3408528SAlexandre.Chartre@Sun.COM */
3418528SAlexandre.Chartre@Sun.COM vdc_flag++;
3420Sstevel@tonic-gate }
3438528SAlexandre.Chartre@Sun.COM
3440Sstevel@tonic-gate /* get the LBA size */
3450Sstevel@tonic-gate if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
3460Sstevel@tonic-gate if (efi_debug) {
3470Sstevel@tonic-gate (void) fprintf(stderr,
3480Sstevel@tonic-gate "assuming LBA 512 bytes %d\n",
3490Sstevel@tonic-gate errno);
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate disk_info.dki_lbsize = DEV_BSIZE;
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate if (disk_info.dki_lbsize == 0) {
3540Sstevel@tonic-gate if (efi_debug) {
3550Sstevel@tonic-gate (void) fprintf(stderr,
3560Sstevel@tonic-gate "efi_read: assuming LBA 512 bytes\n");
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate disk_info.dki_lbsize = DEV_BSIZE;
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * Read the EFI GPT to figure out how many partitions we need
3620Sstevel@tonic-gate * to deal with.
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate dk_ioc.dki_lba = 1;
3650Sstevel@tonic-gate if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
3660Sstevel@tonic-gate label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
3670Sstevel@tonic-gate } else {
3680Sstevel@tonic-gate label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
3696590Syl194034 disk_info.dki_lbsize;
3700Sstevel@tonic-gate if (label_len % disk_info.dki_lbsize) {
3710Sstevel@tonic-gate /* pad to physical sector size */
3720Sstevel@tonic-gate label_len += disk_info.dki_lbsize;
3730Sstevel@tonic-gate label_len &= ~(disk_info.dki_lbsize - 1);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
3780Sstevel@tonic-gate return (VT_ERROR);
3790Sstevel@tonic-gate
3802913Syl194034 dk_ioc.dki_length = disk_info.dki_lbsize;
3810Sstevel@tonic-gate user_length = vtoc->efi_nparts;
3820Sstevel@tonic-gate efi = dk_ioc.dki_data;
3830Sstevel@tonic-gate if (md_flag) {
3842913Syl194034 dk_ioc.dki_length = label_len;
3850Sstevel@tonic-gate if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
3860Sstevel@tonic-gate switch (errno) {
3870Sstevel@tonic-gate case EIO:
3880Sstevel@tonic-gate return (VT_EIO);
3890Sstevel@tonic-gate default:
3900Sstevel@tonic-gate return (VT_ERROR);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate } else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
3943083Scg149915 /*
3953083Scg149915 * No valid label here; try the alternate. Note that here
3963083Scg149915 * we just read GPT header and save it into dk_ioc.data,
3973083Scg149915 * Later, we will read GUID partition entry array if we
3983083Scg149915 * can get valid GPT header.
3993083Scg149915 */
4003083Scg149915
4013083Scg149915 /*
4023083Scg149915 * This is a workaround for legacy systems. In the past, the
4033083Scg149915 * last sector of SCSI disk was invisible on x86 platform. At
4043083Scg149915 * that time, backup label was saved on the next to the last
4053083Scg149915 * sector. It is possible for users to move a disk from previous
4063083Scg149915 * solaris system to present system. Here, we attempt to search
4073083Scg149915 * legacy backup EFI label first.
4083083Scg149915 */
4093083Scg149915 dk_ioc.dki_lba = disk_info.dki_capacity - 2;
4100Sstevel@tonic-gate dk_ioc.dki_length = disk_info.dki_lbsize;
4112285Scg149915 rval = check_label(fd, &dk_ioc);
4123083Scg149915 if (rval == VT_EINVAL) {
4132285Scg149915 /*
4143083Scg149915 * we didn't find legacy backup EFI label, try to
4153083Scg149915 * search backup EFI label in the last block.
4162285Scg149915 */
4173083Scg149915 dk_ioc.dki_lba = disk_info.dki_capacity - 1;
4182285Scg149915 dk_ioc.dki_length = disk_info.dki_lbsize;
4192285Scg149915 rval = check_label(fd, &dk_ioc);
4203083Scg149915 if (rval == 0) {
4213083Scg149915 legacy_label = B_TRUE;
4223083Scg149915 if (efi_debug)
4233083Scg149915 (void) fprintf(stderr,
4243083Scg149915 "efi_read: primary label corrupt; "
4253083Scg149915 "using EFI backup label located on"
4263083Scg149915 " the last block\n");
4272285Scg149915 }
4283083Scg149915 } else {
4293083Scg149915 if ((efi_debug) && (rval == 0))
4303083Scg149915 (void) fprintf(stderr, "efi_read: primary label"
4313083Scg149915 " corrupt; using legacy EFI backup label "
4323083Scg149915 " located on the next to last block\n");
4332285Scg149915 }
4342285Scg149915
4352285Scg149915 if (rval == 0) {
4360Sstevel@tonic-gate dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
4370Sstevel@tonic-gate vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
4380Sstevel@tonic-gate vtoc->efi_nparts =
4390Sstevel@tonic-gate LE_32(efi->efi_gpt_NumberOfPartitionEntries);
4400Sstevel@tonic-gate /*
4413083Scg149915 * Partition tables are between backup GPT header
4423083Scg149915 * table and ParitionEntryLBA (the starting LBA of
4433083Scg149915 * the GUID partition entries array). Now that we
4443083Scg149915 * already got valid GPT header and saved it in
4453083Scg149915 * dk_ioc.dki_data, we try to get GUID partition
4463083Scg149915 * entry array here.
4470Sstevel@tonic-gate */
4489889SLarry.Liu@Sun.COM /* LINTED */
4499889SLarry.Liu@Sun.COM dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
4509889SLarry.Liu@Sun.COM + disk_info.dki_lbsize);
4513083Scg149915 if (legacy_label)
4523083Scg149915 dk_ioc.dki_length = disk_info.dki_capacity - 1 -
4536590Syl194034 dk_ioc.dki_lba;
4543083Scg149915 else
4553083Scg149915 dk_ioc.dki_length = disk_info.dki_capacity - 2 -
4566590Syl194034 dk_ioc.dki_lba;
4570Sstevel@tonic-gate dk_ioc.dki_length *= disk_info.dki_lbsize;
4583083Scg149915 if (dk_ioc.dki_length >
4593083Scg149915 ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
4600Sstevel@tonic-gate rval = VT_EINVAL;
4610Sstevel@tonic-gate } else {
4623083Scg149915 /*
4633083Scg149915 * read GUID partition entry array
4643083Scg149915 */
4650Sstevel@tonic-gate rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate }
4688528SAlexandre.Chartre@Sun.COM
4698528SAlexandre.Chartre@Sun.COM } else if (rval == 0) {
4708528SAlexandre.Chartre@Sun.COM
4712913Syl194034 dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
4729889SLarry.Liu@Sun.COM /* LINTED */
4739889SLarry.Liu@Sun.COM dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
4749889SLarry.Liu@Sun.COM + disk_info.dki_lbsize);
4752913Syl194034 dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
4762913Syl194034 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
4778528SAlexandre.Chartre@Sun.COM
4788528SAlexandre.Chartre@Sun.COM } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
4798528SAlexandre.Chartre@Sun.COM /*
4808528SAlexandre.Chartre@Sun.COM * When the device is a LDoms virtual disk, the DKIOCGETEFI
4818528SAlexandre.Chartre@Sun.COM * ioctl can fail with EINVAL if the virtual disk backend
4828528SAlexandre.Chartre@Sun.COM * is a ZFS volume serviced by a domain running an old version
4838528SAlexandre.Chartre@Sun.COM * of Solaris. This is because the DKIOCGETEFI ioctl was
4848528SAlexandre.Chartre@Sun.COM * initially incorrectly implemented for a ZFS volume and it
4858528SAlexandre.Chartre@Sun.COM * expected the GPT and GPE to be retrieved with a single ioctl.
4868528SAlexandre.Chartre@Sun.COM * So we try to read the GPT and the GPE using that old style
4878528SAlexandre.Chartre@Sun.COM * ioctl.
4888528SAlexandre.Chartre@Sun.COM */
4898528SAlexandre.Chartre@Sun.COM dk_ioc.dki_lba = 1;
4908528SAlexandre.Chartre@Sun.COM dk_ioc.dki_length = label_len;
4918528SAlexandre.Chartre@Sun.COM rval = check_label(fd, &dk_ioc);
4920Sstevel@tonic-gate }
4938528SAlexandre.Chartre@Sun.COM
4940Sstevel@tonic-gate if (rval < 0) {
4950Sstevel@tonic-gate free(efi);
4960Sstevel@tonic-gate return (rval);
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate /* LINTED -- always longlong aligned */
5002913Syl194034 efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * Assemble this into a "dk_gpt" struct for easier
5040Sstevel@tonic-gate * digestibility by applications.
5050Sstevel@tonic-gate */
5060Sstevel@tonic-gate vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
5070Sstevel@tonic-gate vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
5080Sstevel@tonic-gate vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
5090Sstevel@tonic-gate vtoc->efi_lbasize = disk_info.dki_lbsize;
5100Sstevel@tonic-gate vtoc->efi_last_lba = disk_info.dki_capacity - 1;
5110Sstevel@tonic-gate vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
5120Sstevel@tonic-gate vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
5136590Syl194034 vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
5140Sstevel@tonic-gate UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate * If the array the user passed in is too small, set the length
5180Sstevel@tonic-gate * to what it needs to be and return
5190Sstevel@tonic-gate */
5200Sstevel@tonic-gate if (user_length < vtoc->efi_nparts) {
5210Sstevel@tonic-gate return (VT_EINVAL);
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate for (i = 0; i < vtoc->efi_nparts; i++) {
5250Sstevel@tonic-gate
5266590Syl194034 UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
5276590Syl194034 efi_parts[i].efi_gpe_PartitionTypeGUID);
5280Sstevel@tonic-gate
5296590Syl194034 for (j = 0;
5306590Syl194034 j < sizeof (conversion_array)
5316590Syl194034 / sizeof (struct uuid_to_ptag); j++) {
5320Sstevel@tonic-gate
5336590Syl194034 if (bcmp(&vtoc->efi_parts[i].p_guid,
5346590Syl194034 &conversion_array[j].uuid,
5356590Syl194034 sizeof (struct uuid)) == 0) {
5366590Syl194034 vtoc->efi_parts[i].p_tag = j;
5376590Syl194034 break;
5386590Syl194034 }
5396590Syl194034 }
5406590Syl194034 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
5416590Syl194034 continue;
5426590Syl194034 vtoc->efi_parts[i].p_flag =
5436590Syl194034 LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
5446590Syl194034 vtoc->efi_parts[i].p_start =
5456590Syl194034 LE_64(efi_parts[i].efi_gpe_StartingLBA);
5466590Syl194034 vtoc->efi_parts[i].p_size =
5476590Syl194034 LE_64(efi_parts[i].efi_gpe_EndingLBA) -
5480Sstevel@tonic-gate vtoc->efi_parts[i].p_start + 1;
5496590Syl194034 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
5506590Syl194034 vtoc->efi_parts[i].p_name[j] =
5516590Syl194034 (uchar_t)LE_16(
5526590Syl194034 efi_parts[i].efi_gpe_PartitionName[j]);
5536590Syl194034 }
5540Sstevel@tonic-gate
5556590Syl194034 UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
5566590Syl194034 efi_parts[i].efi_gpe_UniquePartitionGUID);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate free(efi);
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate return (dki_info.dki_partition);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate /* writes a "protective" MBR */
5640Sstevel@tonic-gate static int
write_pmbr(int fd,struct dk_gpt * vtoc)5650Sstevel@tonic-gate write_pmbr(int fd, struct dk_gpt *vtoc)
5660Sstevel@tonic-gate {
5670Sstevel@tonic-gate dk_efi_t dk_ioc;
5680Sstevel@tonic-gate struct mboot mb;
5690Sstevel@tonic-gate uchar_t *cp;
5700Sstevel@tonic-gate diskaddr_t size_in_lba;
5719889SLarry.Liu@Sun.COM uchar_t *buf;
5729889SLarry.Liu@Sun.COM int len;
5739889SLarry.Liu@Sun.COM
5749889SLarry.Liu@Sun.COM len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
5759889SLarry.Liu@Sun.COM buf = calloc(len, 1);
5760Sstevel@tonic-gate
5776889Sxl222276 /*
5786889Sxl222276 * Preserve any boot code and disk signature if the first block is
5796889Sxl222276 * already an MBR.
5806889Sxl222276 */
5816889Sxl222276 dk_ioc.dki_lba = 0;
5829889SLarry.Liu@Sun.COM dk_ioc.dki_length = len;
5836889Sxl222276 /* LINTED -- always longlong aligned */
5849889SLarry.Liu@Sun.COM dk_ioc.dki_data = (efi_gpt_t *)buf;
5859889SLarry.Liu@Sun.COM if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
5869889SLarry.Liu@Sun.COM (void *) memcpy(&mb, buf, sizeof (mb));
5876889Sxl222276 bzero(&mb, sizeof (mb));
5886889Sxl222276 mb.signature = LE_16(MBB_MAGIC);
5899889SLarry.Liu@Sun.COM } else {
5909889SLarry.Liu@Sun.COM (void *) memcpy(&mb, buf, sizeof (mb));
5919889SLarry.Liu@Sun.COM if (mb.signature != LE_16(MBB_MAGIC)) {
5929889SLarry.Liu@Sun.COM bzero(&mb, sizeof (mb));
5939889SLarry.Liu@Sun.COM mb.signature = LE_16(MBB_MAGIC);
5949889SLarry.Liu@Sun.COM }
5956889Sxl222276 }
5969889SLarry.Liu@Sun.COM
5970Sstevel@tonic-gate bzero(&mb.parts, sizeof (mb.parts));
5980Sstevel@tonic-gate cp = (uchar_t *)&mb.parts[0];
5990Sstevel@tonic-gate /* bootable or not */
6000Sstevel@tonic-gate *cp++ = 0;
6010Sstevel@tonic-gate /* beginning CHS; 0xffffff if not representable */
6020Sstevel@tonic-gate *cp++ = 0xff;
6030Sstevel@tonic-gate *cp++ = 0xff;
6040Sstevel@tonic-gate *cp++ = 0xff;
6050Sstevel@tonic-gate /* OS type */
6060Sstevel@tonic-gate *cp++ = EFI_PMBR;
6070Sstevel@tonic-gate /* ending CHS; 0xffffff if not representable */
6080Sstevel@tonic-gate *cp++ = 0xff;
6090Sstevel@tonic-gate *cp++ = 0xff;
6100Sstevel@tonic-gate *cp++ = 0xff;
6110Sstevel@tonic-gate /* starting LBA: 1 (little endian format) by EFI definition */
6120Sstevel@tonic-gate *cp++ = 0x01;
6130Sstevel@tonic-gate *cp++ = 0x00;
6140Sstevel@tonic-gate *cp++ = 0x00;
6150Sstevel@tonic-gate *cp++ = 0x00;
6160Sstevel@tonic-gate /* ending LBA: last block on the disk (little endian format) */
6170Sstevel@tonic-gate size_in_lba = vtoc->efi_last_lba;
6180Sstevel@tonic-gate if (size_in_lba < 0xffffffff) {
6190Sstevel@tonic-gate *cp++ = (size_in_lba & 0x000000ff);
6200Sstevel@tonic-gate *cp++ = (size_in_lba & 0x0000ff00) >> 8;
6210Sstevel@tonic-gate *cp++ = (size_in_lba & 0x00ff0000) >> 16;
6220Sstevel@tonic-gate *cp++ = (size_in_lba & 0xff000000) >> 24;
6230Sstevel@tonic-gate } else {
6240Sstevel@tonic-gate *cp++ = 0xff;
6250Sstevel@tonic-gate *cp++ = 0xff;
6260Sstevel@tonic-gate *cp++ = 0xff;
6270Sstevel@tonic-gate *cp++ = 0xff;
6280Sstevel@tonic-gate }
6299889SLarry.Liu@Sun.COM
6309889SLarry.Liu@Sun.COM (void *) memcpy(buf, &mb, sizeof (mb));
6310Sstevel@tonic-gate /* LINTED -- always longlong aligned */
6329889SLarry.Liu@Sun.COM dk_ioc.dki_data = (efi_gpt_t *)buf;
6330Sstevel@tonic-gate dk_ioc.dki_lba = 0;
6349889SLarry.Liu@Sun.COM dk_ioc.dki_length = len;
6350Sstevel@tonic-gate if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
6369889SLarry.Liu@Sun.COM free(buf);
6370Sstevel@tonic-gate switch (errno) {
6380Sstevel@tonic-gate case EIO:
6390Sstevel@tonic-gate return (VT_EIO);
6400Sstevel@tonic-gate case EINVAL:
6410Sstevel@tonic-gate return (VT_EINVAL);
6420Sstevel@tonic-gate default:
6430Sstevel@tonic-gate return (VT_ERROR);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate }
6469889SLarry.Liu@Sun.COM free(buf);
6470Sstevel@tonic-gate return (0);
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate /* make sure the user specified something reasonable */
6510Sstevel@tonic-gate static int
check_input(struct dk_gpt * vtoc)6520Sstevel@tonic-gate check_input(struct dk_gpt *vtoc)
6530Sstevel@tonic-gate {
6540Sstevel@tonic-gate int resv_part = -1;
6550Sstevel@tonic-gate int i, j;
6560Sstevel@tonic-gate diskaddr_t istart, jstart, isize, jsize, endsect;
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate * Sanity-check the input (make sure no partitions overlap)
6600Sstevel@tonic-gate */
6610Sstevel@tonic-gate for (i = 0; i < vtoc->efi_nparts; i++) {
6620Sstevel@tonic-gate /* It can't be unassigned and have an actual size */
6630Sstevel@tonic-gate if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
6640Sstevel@tonic-gate (vtoc->efi_parts[i].p_size != 0)) {
6650Sstevel@tonic-gate if (efi_debug) {
6660Sstevel@tonic-gate (void) fprintf(stderr,
6670Sstevel@tonic-gate "partition %d is \"unassigned\" but has a size of %llu",
6680Sstevel@tonic-gate i,
6690Sstevel@tonic-gate vtoc->efi_parts[i].p_size);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate return (VT_EINVAL);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
6742866Sszhou if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
6752866Sszhou continue;
6762866Sszhou /* we have encountered an unknown uuid */
6772866Sszhou vtoc->efi_parts[i].p_tag = 0xff;
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
6800Sstevel@tonic-gate if (resv_part != -1) {
6810Sstevel@tonic-gate if (efi_debug) {
6826590Syl194034 (void) fprintf(stderr,
6830Sstevel@tonic-gate "found duplicate reserved partition at %d\n",
6846590Syl194034 i);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate return (VT_EINVAL);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate resv_part = i;
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
6910Sstevel@tonic-gate (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
6920Sstevel@tonic-gate if (efi_debug) {
6930Sstevel@tonic-gate (void) fprintf(stderr,
6940Sstevel@tonic-gate "Partition %d starts at %llu. ",
6950Sstevel@tonic-gate i,
6960Sstevel@tonic-gate vtoc->efi_parts[i].p_start);
6970Sstevel@tonic-gate (void) fprintf(stderr,
6980Sstevel@tonic-gate "It must be between %llu and %llu.\n",
6990Sstevel@tonic-gate vtoc->efi_first_u_lba,
7000Sstevel@tonic-gate vtoc->efi_last_u_lba);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate return (VT_EINVAL);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate if ((vtoc->efi_parts[i].p_start +
7050Sstevel@tonic-gate vtoc->efi_parts[i].p_size <
7060Sstevel@tonic-gate vtoc->efi_first_u_lba) ||
7070Sstevel@tonic-gate (vtoc->efi_parts[i].p_start +
7080Sstevel@tonic-gate vtoc->efi_parts[i].p_size >
7090Sstevel@tonic-gate vtoc->efi_last_u_lba + 1)) {
7100Sstevel@tonic-gate if (efi_debug) {
7110Sstevel@tonic-gate (void) fprintf(stderr,
7120Sstevel@tonic-gate "Partition %d ends at %llu. ",
7130Sstevel@tonic-gate i,
7140Sstevel@tonic-gate vtoc->efi_parts[i].p_start +
7150Sstevel@tonic-gate vtoc->efi_parts[i].p_size);
7160Sstevel@tonic-gate (void) fprintf(stderr,
7170Sstevel@tonic-gate "It must be between %llu and %llu.\n",
7180Sstevel@tonic-gate vtoc->efi_first_u_lba,
7190Sstevel@tonic-gate vtoc->efi_last_u_lba);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate return (VT_EINVAL);
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate for (j = 0; j < vtoc->efi_nparts; j++) {
7250Sstevel@tonic-gate isize = vtoc->efi_parts[i].p_size;
7260Sstevel@tonic-gate jsize = vtoc->efi_parts[j].p_size;
7270Sstevel@tonic-gate istart = vtoc->efi_parts[i].p_start;
7280Sstevel@tonic-gate jstart = vtoc->efi_parts[j].p_start;
7290Sstevel@tonic-gate if ((i != j) && (isize != 0) && (jsize != 0)) {
7300Sstevel@tonic-gate endsect = jstart + jsize -1;
7310Sstevel@tonic-gate if ((jstart <= istart) &&
7320Sstevel@tonic-gate (istart <= endsect)) {
7330Sstevel@tonic-gate if (efi_debug) {
7340Sstevel@tonic-gate (void) fprintf(stderr,
7350Sstevel@tonic-gate "Partition %d overlaps partition %d.",
7360Sstevel@tonic-gate i, j);
7376590Syl194034 }
7386590Syl194034 return (VT_EINVAL);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate /* just a warning for now */
7440Sstevel@tonic-gate if ((resv_part == -1) && efi_debug) {
7450Sstevel@tonic-gate (void) fprintf(stderr,
7466590Syl194034 "no reserved partition found\n");
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate return (0);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate /*
7526590Syl194034 * add all the unallocated space to the current label
7536590Syl194034 */
7546590Syl194034 int
efi_use_whole_disk(int fd)7556590Syl194034 efi_use_whole_disk(int fd)
7566590Syl194034 {
7576590Syl194034 struct dk_gpt *efi_label;
7586590Syl194034 int rval;
7596590Syl194034 int i;
7606590Syl194034 uint_t phy_last_slice = 0;
7616590Syl194034 diskaddr_t pl_start = 0;
7626590Syl194034 diskaddr_t pl_size;
7636590Syl194034
7646590Syl194034 rval = efi_alloc_and_read(fd, &efi_label);
7656590Syl194034 if (rval < 0) {
7666590Syl194034 return (rval);
7676590Syl194034 }
7686590Syl194034
7696590Syl194034 /* find the last physically non-zero partition */
7706590Syl194034 for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
7716590Syl194034 if (pl_start < efi_label->efi_parts[i].p_start) {
7726590Syl194034 pl_start = efi_label->efi_parts[i].p_start;
7736590Syl194034 phy_last_slice = i;
7746590Syl194034 }
7756590Syl194034 }
7766590Syl194034 pl_size = efi_label->efi_parts[phy_last_slice].p_size;
7776590Syl194034
7786590Syl194034 /*
7796590Syl194034 * If alter_lba is 1, we are using the backup label.
7806590Syl194034 * Since we can locate the backup label by disk capacity,
7816590Syl194034 * there must be no unallocated space.
7826590Syl194034 */
7836590Syl194034 if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba
7846590Syl194034 >= efi_label->efi_last_lba)) {
7856590Syl194034 if (efi_debug) {
7866590Syl194034 (void) fprintf(stderr,
7876590Syl194034 "efi_use_whole_disk: requested space not found\n");
7886590Syl194034 }
7896590Syl194034 efi_free(efi_label);
7906590Syl194034 return (VT_ENOSPC);
7916590Syl194034 }
7926590Syl194034
7936590Syl194034 /*
7946590Syl194034 * If there is space between the last physically non-zero partition
7956590Syl194034 * and the reserved partition, just add the unallocated space to this
7966590Syl194034 * area. Otherwise, the unallocated space is added to the last
7976590Syl194034 * physically non-zero partition.
7986590Syl194034 */
7996590Syl194034 if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
8006590Syl194034 EFI_MIN_RESV_SIZE) {
8016590Syl194034 efi_label->efi_parts[phy_last_slice].p_size +=
8026590Syl194034 efi_label->efi_last_lba - efi_label->efi_altern_lba;
8036590Syl194034 }
8046590Syl194034
8056590Syl194034 /*
8066590Syl194034 * Move the reserved partition. There is currently no data in
8076590Syl194034 * here except fabricated devids (which get generated via
8086590Syl194034 * efi_write()). So there is no need to copy data.
8096590Syl194034 */
8106590Syl194034 efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
8116590Syl194034 efi_label->efi_last_lba - efi_label->efi_altern_lba;
8126590Syl194034 efi_label->efi_last_u_lba += efi_label->efi_last_lba
8136590Syl194034 - efi_label->efi_altern_lba;
8146590Syl194034
8156590Syl194034 rval = efi_write(fd, efi_label);
8166590Syl194034 if (rval < 0) {
8176590Syl194034 if (efi_debug) {
8186590Syl194034 (void) fprintf(stderr,
8196590Syl194034 "efi_use_whole_disk:fail to write label, rval=%d\n",
8206590Syl194034 rval);
8216590Syl194034 }
8226590Syl194034 efi_free(efi_label);
8236590Syl194034 return (rval);
8246590Syl194034 }
8256590Syl194034
8266590Syl194034 efi_free(efi_label);
8276590Syl194034 return (0);
8286590Syl194034 }
8296590Syl194034
8306590Syl194034
8316590Syl194034 /*
8320Sstevel@tonic-gate * write EFI label and backup label
8330Sstevel@tonic-gate */
8340Sstevel@tonic-gate int
efi_write(int fd,struct dk_gpt * vtoc)8350Sstevel@tonic-gate efi_write(int fd, struct dk_gpt *vtoc)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate dk_efi_t dk_ioc;
8380Sstevel@tonic-gate efi_gpt_t *efi;
8390Sstevel@tonic-gate efi_gpe_t *efi_parts;
8400Sstevel@tonic-gate int i, j;
8410Sstevel@tonic-gate struct dk_cinfo dki_info;
8420Sstevel@tonic-gate int md_flag = 0;
8433083Scg149915 int nblocks;
8443083Scg149915 diskaddr_t lba_backup_gpt_hdr;
8450Sstevel@tonic-gate
8460Sstevel@tonic-gate if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
8470Sstevel@tonic-gate if (efi_debug)
8480Sstevel@tonic-gate (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
8490Sstevel@tonic-gate switch (errno) {
8500Sstevel@tonic-gate case EIO:
8510Sstevel@tonic-gate return (VT_EIO);
8520Sstevel@tonic-gate case EINVAL:
8530Sstevel@tonic-gate return (VT_EINVAL);
8540Sstevel@tonic-gate default:
8550Sstevel@tonic-gate return (VT_ERROR);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate /* check if we are dealing wih a metadevice */
8600Sstevel@tonic-gate if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
8610Sstevel@tonic-gate (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
8620Sstevel@tonic-gate md_flag = 1;
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate if (check_input(vtoc)) {
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate * not valid; if it's a metadevice just pass it down
8680Sstevel@tonic-gate * because SVM will do its own checking
8690Sstevel@tonic-gate */
8700Sstevel@tonic-gate if (md_flag == 0) {
8710Sstevel@tonic-gate return (VT_EINVAL);
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate dk_ioc.dki_lba = 1;
8760Sstevel@tonic-gate if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
8770Sstevel@tonic-gate dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
8780Sstevel@tonic-gate } else {
8790Sstevel@tonic-gate dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
8806590Syl194034 vtoc->efi_lbasize) *
8816590Syl194034 vtoc->efi_lbasize;
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate
8843083Scg149915 /*
8853083Scg149915 * the number of blocks occupied by GUID partition entry array
8863083Scg149915 */
8873083Scg149915 nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
8883083Scg149915
8893083Scg149915 /*
8903083Scg149915 * Backup GPT header is located on the block after GUID
8913083Scg149915 * partition entry array. Here, we calculate the address
8923083Scg149915 * for backup GPT header.
8933083Scg149915 */
8943083Scg149915 lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
8950Sstevel@tonic-gate if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL)
8960Sstevel@tonic-gate return (VT_ERROR);
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate efi = dk_ioc.dki_data;
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate /* stuff user's input into EFI struct */
9010Sstevel@tonic-gate efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
9020Sstevel@tonic-gate efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
9030Sstevel@tonic-gate efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
9040Sstevel@tonic-gate efi->efi_gpt_Reserved1 = 0;
9050Sstevel@tonic-gate efi->efi_gpt_MyLBA = LE_64(1ULL);
9063083Scg149915 efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
9070Sstevel@tonic-gate efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
9080Sstevel@tonic-gate efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
9090Sstevel@tonic-gate efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
9100Sstevel@tonic-gate efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
9110Sstevel@tonic-gate efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
9120Sstevel@tonic-gate UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate /* LINTED -- always longlong aligned */
9159889SLarry.Liu@Sun.COM efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate for (i = 0; i < vtoc->efi_nparts; i++) {
9186590Syl194034 for (j = 0;
9196590Syl194034 j < sizeof (conversion_array) /
9206590Syl194034 sizeof (struct uuid_to_ptag); j++) {
9210Sstevel@tonic-gate
9226590Syl194034 if (vtoc->efi_parts[i].p_tag == j) {
9236590Syl194034 UUID_LE_CONVERT(
9246590Syl194034 efi_parts[i].efi_gpe_PartitionTypeGUID,
9256590Syl194034 conversion_array[j].uuid);
9266590Syl194034 break;
9276590Syl194034 }
9286590Syl194034 }
9292866Sszhou
9306590Syl194034 if (j == sizeof (conversion_array) /
9316590Syl194034 sizeof (struct uuid_to_ptag)) {
9326590Syl194034 /*
9336590Syl194034 * If we didn't have a matching uuid match, bail here.
9346590Syl194034 * Don't write a label with unknown uuid.
9356590Syl194034 */
9366590Syl194034 if (efi_debug) {
9376590Syl194034 (void) fprintf(stderr,
9386590Syl194034 "Unknown uuid for p_tag %d\n",
9396590Syl194034 vtoc->efi_parts[i].p_tag);
9406590Syl194034 }
9416590Syl194034 return (VT_EINVAL);
9426590Syl194034 }
9432866Sszhou
9446590Syl194034 efi_parts[i].efi_gpe_StartingLBA =
9456590Syl194034 LE_64(vtoc->efi_parts[i].p_start);
9466590Syl194034 efi_parts[i].efi_gpe_EndingLBA =
9476590Syl194034 LE_64(vtoc->efi_parts[i].p_start +
9486590Syl194034 vtoc->efi_parts[i].p_size - 1);
9496590Syl194034 efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
9500Sstevel@tonic-gate LE_16(vtoc->efi_parts[i].p_flag);
9516590Syl194034 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
9526590Syl194034 efi_parts[i].efi_gpe_PartitionName[j] =
9536590Syl194034 LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
9546590Syl194034 }
9556590Syl194034 if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
9566590Syl194034 uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
9576590Syl194034 (void) uuid_generate((uchar_t *)
9586590Syl194034 &vtoc->efi_parts[i].p_uguid);
9596590Syl194034 }
9606590Syl194034 bcopy(&vtoc->efi_parts[i].p_uguid,
9616590Syl194034 &efi_parts[i].efi_gpe_UniquePartitionGUID,
9626590Syl194034 sizeof (uuid_t));
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate efi->efi_gpt_PartitionEntryArrayCRC32 =
9650Sstevel@tonic-gate LE_32(efi_crc32((unsigned char *)efi_parts,
9660Sstevel@tonic-gate vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
9670Sstevel@tonic-gate efi->efi_gpt_HeaderCRC32 =
9680Sstevel@tonic-gate LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
9710Sstevel@tonic-gate free(dk_ioc.dki_data);
9720Sstevel@tonic-gate switch (errno) {
9730Sstevel@tonic-gate case EIO:
9740Sstevel@tonic-gate return (VT_EIO);
9750Sstevel@tonic-gate case EINVAL:
9760Sstevel@tonic-gate return (VT_EINVAL);
9770Sstevel@tonic-gate default:
9780Sstevel@tonic-gate return (VT_ERROR);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate /* if it's a metadevice we're done */
9820Sstevel@tonic-gate if (md_flag) {
9830Sstevel@tonic-gate free(dk_ioc.dki_data);
9840Sstevel@tonic-gate return (0);
9850Sstevel@tonic-gate }
9869889SLarry.Liu@Sun.COM
9870Sstevel@tonic-gate /* write backup partition array */
9880Sstevel@tonic-gate dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
9890Sstevel@tonic-gate dk_ioc.dki_length -= vtoc->efi_lbasize;
9909889SLarry.Liu@Sun.COM /* LINTED */
9919889SLarry.Liu@Sun.COM dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
9929889SLarry.Liu@Sun.COM vtoc->efi_lbasize);
9939889SLarry.Liu@Sun.COM
9940Sstevel@tonic-gate if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
9950Sstevel@tonic-gate /*
9960Sstevel@tonic-gate * we wrote the primary label okay, so don't fail
9970Sstevel@tonic-gate */
9980Sstevel@tonic-gate if (efi_debug) {
9990Sstevel@tonic-gate (void) fprintf(stderr,
10000Sstevel@tonic-gate "write of backup partitions to block %llu "
10010Sstevel@tonic-gate "failed, errno %d\n",
10020Sstevel@tonic-gate vtoc->efi_last_u_lba + 1,
10030Sstevel@tonic-gate errno);
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate /*
10070Sstevel@tonic-gate * now swap MyLBA and AlternateLBA fields and write backup
10080Sstevel@tonic-gate * partition table header
10090Sstevel@tonic-gate */
10103083Scg149915 dk_ioc.dki_lba = lba_backup_gpt_hdr;
10110Sstevel@tonic-gate dk_ioc.dki_length = vtoc->efi_lbasize;
10129889SLarry.Liu@Sun.COM /* LINTED */
10139889SLarry.Liu@Sun.COM dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
10149889SLarry.Liu@Sun.COM vtoc->efi_lbasize);
10150Sstevel@tonic-gate efi->efi_gpt_AlternateLBA = LE_64(1ULL);
10163083Scg149915 efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
10170Sstevel@tonic-gate efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
10180Sstevel@tonic-gate efi->efi_gpt_HeaderCRC32 = 0;
10190Sstevel@tonic-gate efi->efi_gpt_HeaderCRC32 =
10200Sstevel@tonic-gate LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
10210Sstevel@tonic-gate sizeof (struct efi_gpt)));
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
10240Sstevel@tonic-gate if (efi_debug) {
10250Sstevel@tonic-gate (void) fprintf(stderr,
10260Sstevel@tonic-gate "write of backup header to block %llu failed, "
10270Sstevel@tonic-gate "errno %d\n",
10283083Scg149915 lba_backup_gpt_hdr,
10290Sstevel@tonic-gate errno);
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate /* write the PMBR */
10330Sstevel@tonic-gate (void) write_pmbr(fd, vtoc);
10340Sstevel@tonic-gate free(dk_ioc.dki_data);
10350Sstevel@tonic-gate return (0);
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate void
efi_free(struct dk_gpt * ptr)10390Sstevel@tonic-gate efi_free(struct dk_gpt *ptr)
10400Sstevel@tonic-gate {
10410Sstevel@tonic-gate free(ptr);
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate /*
10450Sstevel@tonic-gate * Input: File descriptor
10467563SPrasad.Singamsetty@Sun.COM * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
10477563SPrasad.Singamsetty@Sun.COM * Otherwise 0.
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate int
efi_type(int fd)10500Sstevel@tonic-gate efi_type(int fd)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate struct vtoc vtoc;
10537563SPrasad.Singamsetty@Sun.COM struct extvtoc extvtoc;
10540Sstevel@tonic-gate
10557563SPrasad.Singamsetty@Sun.COM if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) {
10567563SPrasad.Singamsetty@Sun.COM if (errno == ENOTSUP)
10570Sstevel@tonic-gate return (1);
10587563SPrasad.Singamsetty@Sun.COM else if (errno == ENOTTY) {
10597563SPrasad.Singamsetty@Sun.COM if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1)
10607563SPrasad.Singamsetty@Sun.COM if (errno == ENOTSUP)
10617563SPrasad.Singamsetty@Sun.COM return (1);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate return (0);
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate void
efi_err_check(struct dk_gpt * vtoc)10680Sstevel@tonic-gate efi_err_check(struct dk_gpt *vtoc)
10690Sstevel@tonic-gate {
10700Sstevel@tonic-gate int resv_part = -1;
10710Sstevel@tonic-gate int i, j;
10720Sstevel@tonic-gate diskaddr_t istart, jstart, isize, jsize, endsect;
10730Sstevel@tonic-gate int overlap = 0;
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate /*
10760Sstevel@tonic-gate * make sure no partitions overlap
10770Sstevel@tonic-gate */
10780Sstevel@tonic-gate for (i = 0; i < vtoc->efi_nparts; i++) {
10790Sstevel@tonic-gate /* It can't be unassigned and have an actual size */
10800Sstevel@tonic-gate if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
10810Sstevel@tonic-gate (vtoc->efi_parts[i].p_size != 0)) {
10820Sstevel@tonic-gate (void) fprintf(stderr,
10830Sstevel@tonic-gate "partition %d is \"unassigned\" but has a size "
10840Sstevel@tonic-gate "of %llu\n", i, vtoc->efi_parts[i].p_size);
10850Sstevel@tonic-gate }
10860Sstevel@tonic-gate if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
10870Sstevel@tonic-gate continue;
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
10900Sstevel@tonic-gate if (resv_part != -1) {
10910Sstevel@tonic-gate (void) fprintf(stderr,
10920Sstevel@tonic-gate "found duplicate reserved partition at "
10930Sstevel@tonic-gate "%d\n", i);
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate resv_part = i;
10960Sstevel@tonic-gate if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
10970Sstevel@tonic-gate (void) fprintf(stderr,
10980Sstevel@tonic-gate "Warning: reserved partition size must "
10990Sstevel@tonic-gate "be %d sectors\n", EFI_MIN_RESV_SIZE);
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
11020Sstevel@tonic-gate (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
11030Sstevel@tonic-gate (void) fprintf(stderr,
11040Sstevel@tonic-gate "Partition %d starts at %llu\n",
11050Sstevel@tonic-gate i,
11060Sstevel@tonic-gate vtoc->efi_parts[i].p_start);
11070Sstevel@tonic-gate (void) fprintf(stderr,
11080Sstevel@tonic-gate "It must be between %llu and %llu.\n",
11090Sstevel@tonic-gate vtoc->efi_first_u_lba,
11100Sstevel@tonic-gate vtoc->efi_last_u_lba);
11110Sstevel@tonic-gate }
11120Sstevel@tonic-gate if ((vtoc->efi_parts[i].p_start +
11130Sstevel@tonic-gate vtoc->efi_parts[i].p_size <
11140Sstevel@tonic-gate vtoc->efi_first_u_lba) ||
11150Sstevel@tonic-gate (vtoc->efi_parts[i].p_start +
11160Sstevel@tonic-gate vtoc->efi_parts[i].p_size >
11170Sstevel@tonic-gate vtoc->efi_last_u_lba + 1)) {
11180Sstevel@tonic-gate (void) fprintf(stderr,
11190Sstevel@tonic-gate "Partition %d ends at %llu\n",
11200Sstevel@tonic-gate i,
11210Sstevel@tonic-gate vtoc->efi_parts[i].p_start +
11220Sstevel@tonic-gate vtoc->efi_parts[i].p_size);
11230Sstevel@tonic-gate (void) fprintf(stderr,
11240Sstevel@tonic-gate "It must be between %llu and %llu.\n",
11250Sstevel@tonic-gate vtoc->efi_first_u_lba,
11260Sstevel@tonic-gate vtoc->efi_last_u_lba);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate for (j = 0; j < vtoc->efi_nparts; j++) {
11300Sstevel@tonic-gate isize = vtoc->efi_parts[i].p_size;
11310Sstevel@tonic-gate jsize = vtoc->efi_parts[j].p_size;
11320Sstevel@tonic-gate istart = vtoc->efi_parts[i].p_start;
11330Sstevel@tonic-gate jstart = vtoc->efi_parts[j].p_start;
11340Sstevel@tonic-gate if ((i != j) && (isize != 0) && (jsize != 0)) {
11350Sstevel@tonic-gate endsect = jstart + jsize -1;
11360Sstevel@tonic-gate if ((jstart <= istart) &&
11370Sstevel@tonic-gate (istart <= endsect)) {
11380Sstevel@tonic-gate if (!overlap) {
11390Sstevel@tonic-gate (void) fprintf(stderr,
11400Sstevel@tonic-gate "label error: EFI Labels do not "
11410Sstevel@tonic-gate "support overlapping partitions\n");
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate (void) fprintf(stderr,
11440Sstevel@tonic-gate "Partition %d overlaps partition "
11450Sstevel@tonic-gate "%d.\n", i, j);
11460Sstevel@tonic-gate overlap = 1;
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate /* make sure there is a reserved partition */
11520Sstevel@tonic-gate if (resv_part == -1) {
11530Sstevel@tonic-gate (void) fprintf(stderr,
11546590Syl194034 "no reserved partition found\n");
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate /*
11590Sstevel@tonic-gate * We need to get information necessary to construct a *new* efi
11600Sstevel@tonic-gate * label type
11610Sstevel@tonic-gate */
11620Sstevel@tonic-gate int
efi_auto_sense(int fd,struct dk_gpt ** vtoc)11630Sstevel@tonic-gate efi_auto_sense(int fd, struct dk_gpt **vtoc)
11640Sstevel@tonic-gate {
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate int i;
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate /*
11690Sstevel@tonic-gate * Now build the default partition table
11700Sstevel@tonic-gate */
11710Sstevel@tonic-gate if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
11720Sstevel@tonic-gate if (efi_debug) {
11730Sstevel@tonic-gate (void) fprintf(stderr, "efi_alloc_and_init failed.\n");
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate return (-1);
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
11790Sstevel@tonic-gate (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
11800Sstevel@tonic-gate (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
11810Sstevel@tonic-gate (*vtoc)->efi_parts[i].p_start = 0;
11820Sstevel@tonic-gate (*vtoc)->efi_parts[i].p_size = 0;
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate /*
11850Sstevel@tonic-gate * Make constants first
11860Sstevel@tonic-gate * and variable partitions later
11870Sstevel@tonic-gate */
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate /* root partition - s0 128 MB */
11900Sstevel@tonic-gate (*vtoc)->efi_parts[0].p_start = 34;
11910Sstevel@tonic-gate (*vtoc)->efi_parts[0].p_size = 262144;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /* partition - s1 128 MB */
11940Sstevel@tonic-gate (*vtoc)->efi_parts[1].p_start = 262178;
11950Sstevel@tonic-gate (*vtoc)->efi_parts[1].p_size = 262144;
11960Sstevel@tonic-gate
11970Sstevel@tonic-gate /* partition -s2 is NOT the Backup disk */
11980Sstevel@tonic-gate (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate /* partition -s6 /usr partition - HOG */
12010Sstevel@tonic-gate (*vtoc)->efi_parts[6].p_start = 524322;
12020Sstevel@tonic-gate (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
12030Sstevel@tonic-gate - (1024 * 16);
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate /* efi reserved partition - s9 16K */
12060Sstevel@tonic-gate (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
12070Sstevel@tonic-gate (*vtoc)->efi_parts[8].p_size = (1024 * 16);
12080Sstevel@tonic-gate (*vtoc)->efi_parts[8].p_tag = V_RESERVED;
12090Sstevel@tonic-gate return (0);
12100Sstevel@tonic-gate }
1211