1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <errno.h>
32*7c478bd9Sstevel@tonic-gate #include <strings.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <uuid/uuid.h>
35*7c478bd9Sstevel@tonic-gate #include <libintl.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/mhd.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/efi_partition.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate static struct uuid_to_ptag {
47*7c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
48*7c478bd9Sstevel@tonic-gate } conversion_array[] = {
49*7c478bd9Sstevel@tonic-gate 	{ EFI_UNUSED },
50*7c478bd9Sstevel@tonic-gate 	{ EFI_BOOT },
51*7c478bd9Sstevel@tonic-gate 	{ EFI_ROOT },
52*7c478bd9Sstevel@tonic-gate 	{ EFI_SWAP },
53*7c478bd9Sstevel@tonic-gate 	{ EFI_USR },
54*7c478bd9Sstevel@tonic-gate 	{ EFI_BACKUP },
55*7c478bd9Sstevel@tonic-gate 	{ 0 },			/* STAND is never used */
56*7c478bd9Sstevel@tonic-gate 	{ EFI_VAR },
57*7c478bd9Sstevel@tonic-gate 	{ EFI_HOME },
58*7c478bd9Sstevel@tonic-gate 	{ EFI_ALTSCTR },
59*7c478bd9Sstevel@tonic-gate 	{ 0 },			/* CACHE (cachefs) is never used */
60*7c478bd9Sstevel@tonic-gate 	{ EFI_RESERVED },
61*7c478bd9Sstevel@tonic-gate 	{ EFI_SYSTEM },
62*7c478bd9Sstevel@tonic-gate 	{ EFI_LEGACY_MBR },
63*7c478bd9Sstevel@tonic-gate 	{ EFI_RESV3 },
64*7c478bd9Sstevel@tonic-gate 	{ EFI_RESV4 },
65*7c478bd9Sstevel@tonic-gate 	{ EFI_MSFT_RESV },
66*7c478bd9Sstevel@tonic-gate 	{ EFI_DELL_BASIC },
67*7c478bd9Sstevel@tonic-gate 	{ EFI_DELL_RAID },
68*7c478bd9Sstevel@tonic-gate 	{ EFI_DELL_SWAP },
69*7c478bd9Sstevel@tonic-gate 	{ EFI_DELL_LVM },
70*7c478bd9Sstevel@tonic-gate 	{ EFI_DELL_RESV }
71*7c478bd9Sstevel@tonic-gate };
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * Default vtoc information for non-SVr4 partitions
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate struct dk_map2  default_vtoc_map[NDKMAP] = {
77*7c478bd9Sstevel@tonic-gate 	{	V_ROOT,		0	},		/* a - 0 */
78*7c478bd9Sstevel@tonic-gate 	{	V_SWAP,		V_UNMNT	},		/* b - 1 */
79*7c478bd9Sstevel@tonic-gate 	{	V_BACKUP,	V_UNMNT	},		/* c - 2 */
80*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* d - 3 */
81*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* e - 4 */
82*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* f - 5 */
83*7c478bd9Sstevel@tonic-gate 	{	V_USR,		0	},		/* g - 6 */
84*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* h - 7 */
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #if defined(_SUNOS_VTOC_16)
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate #if defined(i386) || defined(__amd64)
89*7c478bd9Sstevel@tonic-gate 	{	V_BOOT,		V_UNMNT	},		/* i - 8 */
90*7c478bd9Sstevel@tonic-gate 	{	V_ALTSCTR,	0	},		/* j - 9 */
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #else
93*7c478bd9Sstevel@tonic-gate #error No VTOC format defined.
94*7c478bd9Sstevel@tonic-gate #endif			/* defined(i386) */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* k - 10 */
97*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* l - 11 */
98*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* m - 12 */
99*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* n - 13 */
100*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* o - 14 */
101*7c478bd9Sstevel@tonic-gate 	{	V_UNASSIGNED,	0	},		/* p - 15 */
102*7c478bd9Sstevel@tonic-gate #endif			/* defined(_SUNOS_VTOC_16) */
103*7c478bd9Sstevel@tonic-gate };
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * This is the size of the reserved partition.
107*7c478bd9Sstevel@tonic-gate  * Valid in case of EFI labels.
108*7c478bd9Sstevel@tonic-gate  */
109*7c478bd9Sstevel@tonic-gate #define	EFI_MIN_RESV_SIZE	(16 * 1024)
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
112*7c478bd9Sstevel@tonic-gate int efi_debug = 1;
113*7c478bd9Sstevel@tonic-gate #else
114*7c478bd9Sstevel@tonic-gate int efi_debug = 0;
115*7c478bd9Sstevel@tonic-gate #endif
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate extern unsigned int	efi_crc32(const unsigned char *, unsigned int);
118*7c478bd9Sstevel@tonic-gate static int		efi_read(int, struct dk_gpt *);
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate static int
121*7c478bd9Sstevel@tonic-gate read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	struct dk_minfo		disk_info;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
126*7c478bd9Sstevel@tonic-gate 		return (errno);
127*7c478bd9Sstevel@tonic-gate 	*capacity = disk_info.dki_capacity;
128*7c478bd9Sstevel@tonic-gate 	*lbsize = disk_info.dki_lbsize;
129*7c478bd9Sstevel@tonic-gate 	return (0);
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate /*
133*7c478bd9Sstevel@tonic-gate  * the number of blocks the EFI label takes up (round up to nearest
134*7c478bd9Sstevel@tonic-gate  * block)
135*7c478bd9Sstevel@tonic-gate  */
136*7c478bd9Sstevel@tonic-gate #define	NBLOCKS(p, l)	(1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
137*7c478bd9Sstevel@tonic-gate 				((l) - 1)) / (l)))
138*7c478bd9Sstevel@tonic-gate /* number of partitions -- limited by what we can malloc */
139*7c478bd9Sstevel@tonic-gate #define	MAX_PARTS	((4294967295UL - sizeof (struct dk_gpt)) / \
140*7c478bd9Sstevel@tonic-gate 			    sizeof (struct dk_part))
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate int
143*7c478bd9Sstevel@tonic-gate efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
144*7c478bd9Sstevel@tonic-gate {
145*7c478bd9Sstevel@tonic-gate 	diskaddr_t	capacity;
146*7c478bd9Sstevel@tonic-gate 	uint_t		lbsize;
147*7c478bd9Sstevel@tonic-gate 	uint_t		nblocks;
148*7c478bd9Sstevel@tonic-gate 	size_t		length;
149*7c478bd9Sstevel@tonic-gate 	struct dk_gpt	*vptr;
150*7c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	if (read_disk_info(fd, &capacity, &lbsize) != 0) {
153*7c478bd9Sstevel@tonic-gate 		if (efi_debug)
154*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
155*7c478bd9Sstevel@tonic-gate 			    "couldn't read disk information\n");
156*7c478bd9Sstevel@tonic-gate 		return (-1);
157*7c478bd9Sstevel@tonic-gate 	}
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	nblocks = NBLOCKS(nparts, lbsize);
160*7c478bd9Sstevel@tonic-gate 	if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
161*7c478bd9Sstevel@tonic-gate 		/* 16K plus one block for the GPT */
162*7c478bd9Sstevel@tonic-gate 		nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	if (nparts > MAX_PARTS) {
166*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
167*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
168*7c478bd9Sstevel@tonic-gate 			"the maximum number of partitions supported is %lu\n",
169*7c478bd9Sstevel@tonic-gate 			    MAX_PARTS);
170*7c478bd9Sstevel@tonic-gate 		}
171*7c478bd9Sstevel@tonic-gate 		return (-1);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	length = sizeof (struct dk_gpt) +
175*7c478bd9Sstevel@tonic-gate 	    sizeof (struct dk_part) * (nparts - 1);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	if ((*vtoc = calloc(length, 1)) == NULL)
178*7c478bd9Sstevel@tonic-gate 		return (-1);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	vptr = *vtoc;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	vptr->efi_version = EFI_VERSION_CURRENT;
183*7c478bd9Sstevel@tonic-gate 	vptr->efi_lbasize = lbsize;
184*7c478bd9Sstevel@tonic-gate 	vptr->efi_nparts = nparts;
185*7c478bd9Sstevel@tonic-gate 	/*
186*7c478bd9Sstevel@tonic-gate 	 * add one block here for the PMBR; on disks with a 512 byte
187*7c478bd9Sstevel@tonic-gate 	 * block size and 128 or fewer partitions, efi_first_u_lba
188*7c478bd9Sstevel@tonic-gate 	 * should work out to "34"
189*7c478bd9Sstevel@tonic-gate 	 */
190*7c478bd9Sstevel@tonic-gate 	vptr->efi_first_u_lba = nblocks + 1;
191*7c478bd9Sstevel@tonic-gate 	vptr->efi_last_lba = capacity - 1;
192*7c478bd9Sstevel@tonic-gate 	vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
193*7c478bd9Sstevel@tonic-gate 	(void) uuid_generate((uchar_t *)&uuid);
194*7c478bd9Sstevel@tonic-gate 	UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
195*7c478bd9Sstevel@tonic-gate 	return (0);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate  * Read EFI - return partition number upon success.
200*7c478bd9Sstevel@tonic-gate  */
201*7c478bd9Sstevel@tonic-gate int
202*7c478bd9Sstevel@tonic-gate efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	int			rval;
205*7c478bd9Sstevel@tonic-gate 	uint32_t		nparts;
206*7c478bd9Sstevel@tonic-gate 	int			length;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	/* figure out the number of entries that would fit into 16K */
209*7c478bd9Sstevel@tonic-gate 	nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
210*7c478bd9Sstevel@tonic-gate 	length = (int) sizeof (struct dk_gpt) +
211*7c478bd9Sstevel@tonic-gate 			    (int) sizeof (struct dk_part) * (nparts - 1);
212*7c478bd9Sstevel@tonic-gate 	if ((*vtoc = calloc(length, 1)) == NULL)
213*7c478bd9Sstevel@tonic-gate 		return (VT_ERROR);
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_nparts = nparts;
216*7c478bd9Sstevel@tonic-gate 	rval = efi_read(fd, *vtoc);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
219*7c478bd9Sstevel@tonic-gate 		void *tmp;
220*7c478bd9Sstevel@tonic-gate 		length = (int) sizeof (struct dk_gpt) +
221*7c478bd9Sstevel@tonic-gate 				(int) sizeof (struct dk_part) *
222*7c478bd9Sstevel@tonic-gate 				((*vtoc)->efi_nparts - 1);
223*7c478bd9Sstevel@tonic-gate 		nparts = (*vtoc)->efi_nparts;
224*7c478bd9Sstevel@tonic-gate 		if ((tmp = realloc(*vtoc, length)) == NULL) {
225*7c478bd9Sstevel@tonic-gate 			free (*vtoc);
226*7c478bd9Sstevel@tonic-gate 			*vtoc = NULL;
227*7c478bd9Sstevel@tonic-gate 			return (VT_ERROR);
228*7c478bd9Sstevel@tonic-gate 		} else {
229*7c478bd9Sstevel@tonic-gate 			*vtoc = tmp;
230*7c478bd9Sstevel@tonic-gate 			rval = efi_read(fd, *vtoc);
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	if (rval < 0) {
235*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
236*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
237*7c478bd9Sstevel@tonic-gate 			    "read of EFI table failed, rval=%d\n", rval);
238*7c478bd9Sstevel@tonic-gate 		}
239*7c478bd9Sstevel@tonic-gate 		free (*vtoc);
240*7c478bd9Sstevel@tonic-gate 		*vtoc = NULL;
241*7c478bd9Sstevel@tonic-gate 	}
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	return (rval);
244*7c478bd9Sstevel@tonic-gate }
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate static int
247*7c478bd9Sstevel@tonic-gate efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	void *data = dk_ioc->dki_data;
250*7c478bd9Sstevel@tonic-gate 	int error;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
253*7c478bd9Sstevel@tonic-gate 	error = ioctl(fd, cmd, (void *)dk_ioc);
254*7c478bd9Sstevel@tonic-gate 	dk_ioc->dki_data = data;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	return (error);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate static int
260*7c478bd9Sstevel@tonic-gate check_label(int fd, dk_efi_t *dk_ioc)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	efi_gpt_t		*efi;
263*7c478bd9Sstevel@tonic-gate 	uint_t			crc;
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
266*7c478bd9Sstevel@tonic-gate 		switch (errno) {
267*7c478bd9Sstevel@tonic-gate 		case EIO:
268*7c478bd9Sstevel@tonic-gate 			return (VT_EIO);
269*7c478bd9Sstevel@tonic-gate 		default:
270*7c478bd9Sstevel@tonic-gate 			return (VT_ERROR);
271*7c478bd9Sstevel@tonic-gate 		}
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 	efi = dk_ioc->dki_data;
274*7c478bd9Sstevel@tonic-gate 	if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
275*7c478bd9Sstevel@tonic-gate 		if (efi_debug)
276*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
277*7c478bd9Sstevel@tonic-gate 			    "Bad EFI signature: 0x%llx != 0x%llx\n",
278*7c478bd9Sstevel@tonic-gate 			    (long long)efi->efi_gpt_Signature,
279*7c478bd9Sstevel@tonic-gate 			    (long long)LE_64(EFI_SIGNATURE));
280*7c478bd9Sstevel@tonic-gate 		return (VT_EINVAL);
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/*
284*7c478bd9Sstevel@tonic-gate 	 * check CRC of the header; the size of the header should
285*7c478bd9Sstevel@tonic-gate 	 * never be larger than one block
286*7c478bd9Sstevel@tonic-gate 	 */
287*7c478bd9Sstevel@tonic-gate 	crc = efi->efi_gpt_HeaderCRC32;
288*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_HeaderCRC32 = 0;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
291*7c478bd9Sstevel@tonic-gate 	    crc != LE_32(efi_crc32((unsigned char *)efi,
292*7c478bd9Sstevel@tonic-gate 	    LE_32(efi->efi_gpt_HeaderSize)))) {
293*7c478bd9Sstevel@tonic-gate 		if (efi_debug)
294*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
295*7c478bd9Sstevel@tonic-gate 				"Bad EFI CRC: 0x%x != 0x%x\n",
296*7c478bd9Sstevel@tonic-gate 				crc,
297*7c478bd9Sstevel@tonic-gate 				LE_32(efi_crc32((unsigned char *)efi,
298*7c478bd9Sstevel@tonic-gate 				    sizeof (struct efi_gpt))));
299*7c478bd9Sstevel@tonic-gate 		return (VT_EINVAL);
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	return (0);
303*7c478bd9Sstevel@tonic-gate }
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate static int
306*7c478bd9Sstevel@tonic-gate efi_read(int fd, struct dk_gpt *vtoc)
307*7c478bd9Sstevel@tonic-gate {
308*7c478bd9Sstevel@tonic-gate 	int			i, j;
309*7c478bd9Sstevel@tonic-gate 	int			label_len;
310*7c478bd9Sstevel@tonic-gate 	int			rval = 0;
311*7c478bd9Sstevel@tonic-gate 	int			md_flag = 0;
312*7c478bd9Sstevel@tonic-gate 	struct dk_minfo		disk_info;
313*7c478bd9Sstevel@tonic-gate 	dk_efi_t		dk_ioc;
314*7c478bd9Sstevel@tonic-gate 	efi_gpt_t		*efi;
315*7c478bd9Sstevel@tonic-gate 	efi_gpe_t		*efi_parts;
316*7c478bd9Sstevel@tonic-gate 	struct dk_cinfo		dki_info;
317*7c478bd9Sstevel@tonic-gate 	uint32_t		user_length;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	/*
320*7c478bd9Sstevel@tonic-gate 	 * get the partition number for this file descriptor.
321*7c478bd9Sstevel@tonic-gate 	 */
322*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
323*7c478bd9Sstevel@tonic-gate 		if (efi_debug)
324*7c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
325*7c478bd9Sstevel@tonic-gate 		switch (errno) {
326*7c478bd9Sstevel@tonic-gate 		case EIO:
327*7c478bd9Sstevel@tonic-gate 			return (VT_EIO);
328*7c478bd9Sstevel@tonic-gate 		case EINVAL:
329*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
330*7c478bd9Sstevel@tonic-gate 		default:
331*7c478bd9Sstevel@tonic-gate 			return (VT_ERROR);
332*7c478bd9Sstevel@tonic-gate 		}
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate 	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
335*7c478bd9Sstevel@tonic-gate 	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
336*7c478bd9Sstevel@tonic-gate 		md_flag++;
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 	/* get the LBA size */
339*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
340*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
341*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
342*7c478bd9Sstevel@tonic-gate 			    "assuming LBA 512 bytes %d\n",
343*7c478bd9Sstevel@tonic-gate 			    errno);
344*7c478bd9Sstevel@tonic-gate 		}
345*7c478bd9Sstevel@tonic-gate 		disk_info.dki_lbsize = DEV_BSIZE;
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate 	if (disk_info.dki_lbsize == 0) {
348*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
349*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
350*7c478bd9Sstevel@tonic-gate 			    "efi_read: assuming LBA 512 bytes\n");
351*7c478bd9Sstevel@tonic-gate 		}
352*7c478bd9Sstevel@tonic-gate 		disk_info.dki_lbsize = DEV_BSIZE;
353*7c478bd9Sstevel@tonic-gate 	}
354*7c478bd9Sstevel@tonic-gate 	/*
355*7c478bd9Sstevel@tonic-gate 	 * Read the EFI GPT to figure out how many partitions we need
356*7c478bd9Sstevel@tonic-gate 	 * to deal with.
357*7c478bd9Sstevel@tonic-gate 	 */
358*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_lba = 1;
359*7c478bd9Sstevel@tonic-gate 	if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
360*7c478bd9Sstevel@tonic-gate 		label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
361*7c478bd9Sstevel@tonic-gate 	} else {
362*7c478bd9Sstevel@tonic-gate 		label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
363*7c478bd9Sstevel@tonic-gate 				    disk_info.dki_lbsize;
364*7c478bd9Sstevel@tonic-gate 		if (label_len % disk_info.dki_lbsize) {
365*7c478bd9Sstevel@tonic-gate 			/* pad to physical sector size */
366*7c478bd9Sstevel@tonic-gate 			label_len += disk_info.dki_lbsize;
367*7c478bd9Sstevel@tonic-gate 			label_len &= ~(disk_info.dki_lbsize - 1);
368*7c478bd9Sstevel@tonic-gate 		}
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
372*7c478bd9Sstevel@tonic-gate 		return (VT_ERROR);
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_length = label_len;
375*7c478bd9Sstevel@tonic-gate 	user_length = vtoc->efi_nparts;
376*7c478bd9Sstevel@tonic-gate 	efi = dk_ioc.dki_data;
377*7c478bd9Sstevel@tonic-gate 	if (md_flag) {
378*7c478bd9Sstevel@tonic-gate 		if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
379*7c478bd9Sstevel@tonic-gate 			switch (errno) {
380*7c478bd9Sstevel@tonic-gate 			case EIO:
381*7c478bd9Sstevel@tonic-gate 				return (VT_EIO);
382*7c478bd9Sstevel@tonic-gate 			default:
383*7c478bd9Sstevel@tonic-gate 				return (VT_ERROR);
384*7c478bd9Sstevel@tonic-gate 			}
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 	} else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
387*7c478bd9Sstevel@tonic-gate 		/* no valid label here; try the alternate */
388*7c478bd9Sstevel@tonic-gate 		dk_ioc.dki_lba = disk_info.dki_capacity - 1;
389*7c478bd9Sstevel@tonic-gate 		dk_ioc.dki_length = disk_info.dki_lbsize;
390*7c478bd9Sstevel@tonic-gate 		if (check_label(fd, &dk_ioc) == 0) {
391*7c478bd9Sstevel@tonic-gate 			if (efi_debug) {
392*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
393*7c478bd9Sstevel@tonic-gate 				    "efi_read: primary label corrupt; "
394*7c478bd9Sstevel@tonic-gate 				    "using backup\n");
395*7c478bd9Sstevel@tonic-gate 			}
396*7c478bd9Sstevel@tonic-gate 			dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
397*7c478bd9Sstevel@tonic-gate 			vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
398*7c478bd9Sstevel@tonic-gate 			vtoc->efi_nparts =
399*7c478bd9Sstevel@tonic-gate 			    LE_32(efi->efi_gpt_NumberOfPartitionEntries);
400*7c478bd9Sstevel@tonic-gate 			/*
401*7c478bd9Sstevel@tonic-gate 			 * partitions are between last usable LBA and
402*7c478bd9Sstevel@tonic-gate 			 * backup partition header
403*7c478bd9Sstevel@tonic-gate 			 */
404*7c478bd9Sstevel@tonic-gate 			dk_ioc.dki_data++;
405*7c478bd9Sstevel@tonic-gate 			dk_ioc.dki_length = disk_info.dki_capacity -
406*7c478bd9Sstevel@tonic-gate 						    dk_ioc.dki_lba - 1;
407*7c478bd9Sstevel@tonic-gate 			dk_ioc.dki_length *= disk_info.dki_lbsize;
408*7c478bd9Sstevel@tonic-gate 			if (dk_ioc.dki_length > (len_t)label_len) {
409*7c478bd9Sstevel@tonic-gate 				rval = VT_EINVAL;
410*7c478bd9Sstevel@tonic-gate 			} else {
411*7c478bd9Sstevel@tonic-gate 				rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
412*7c478bd9Sstevel@tonic-gate 			}
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 	}
415*7c478bd9Sstevel@tonic-gate 	if (rval < 0) {
416*7c478bd9Sstevel@tonic-gate 		free(efi);
417*7c478bd9Sstevel@tonic-gate 		return (rval);
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	/* partitions start in the next block */
421*7c478bd9Sstevel@tonic-gate 	/* LINTED -- always longlong aligned */
422*7c478bd9Sstevel@tonic-gate 	efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	/*
425*7c478bd9Sstevel@tonic-gate 	 * Assemble this into a "dk_gpt" struct for easier
426*7c478bd9Sstevel@tonic-gate 	 * digestibility by applications.
427*7c478bd9Sstevel@tonic-gate 	 */
428*7c478bd9Sstevel@tonic-gate 	vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
429*7c478bd9Sstevel@tonic-gate 	vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
430*7c478bd9Sstevel@tonic-gate 	vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
431*7c478bd9Sstevel@tonic-gate 	vtoc->efi_lbasize = disk_info.dki_lbsize;
432*7c478bd9Sstevel@tonic-gate 	vtoc->efi_last_lba = disk_info.dki_capacity - 1;
433*7c478bd9Sstevel@tonic-gate 	vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
434*7c478bd9Sstevel@tonic-gate 	vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
435*7c478bd9Sstevel@tonic-gate 	UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	/*
438*7c478bd9Sstevel@tonic-gate 	 * If the array the user passed in is too small, set the length
439*7c478bd9Sstevel@tonic-gate 	 * to what it needs to be and return
440*7c478bd9Sstevel@tonic-gate 	 */
441*7c478bd9Sstevel@tonic-gate 	if (user_length < vtoc->efi_nparts) {
442*7c478bd9Sstevel@tonic-gate 		return (VT_EINVAL);
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < vtoc->efi_nparts; i++) {
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
448*7c478bd9Sstevel@tonic-gate 		efi_parts[i].efi_gpe_PartitionTypeGUID);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	    for (j = 0;
451*7c478bd9Sstevel@tonic-gate 		j < sizeof (conversion_array) / sizeof (struct uuid_to_ptag);
452*7c478bd9Sstevel@tonic-gate 		j++) {
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 		    if (bcmp(&vtoc->efi_parts[i].p_guid,
455*7c478bd9Sstevel@tonic-gate 			&conversion_array[j].uuid,
456*7c478bd9Sstevel@tonic-gate 			sizeof (struct uuid)) == 0) {
457*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_parts[i].p_tag = j;
458*7c478bd9Sstevel@tonic-gate 			    break;
459*7c478bd9Sstevel@tonic-gate 		    }
460*7c478bd9Sstevel@tonic-gate 	    }
461*7c478bd9Sstevel@tonic-gate 	    if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
462*7c478bd9Sstevel@tonic-gate 		    continue;
463*7c478bd9Sstevel@tonic-gate 	    vtoc->efi_parts[i].p_flag =
464*7c478bd9Sstevel@tonic-gate 		LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
465*7c478bd9Sstevel@tonic-gate 	    vtoc->efi_parts[i].p_start =
466*7c478bd9Sstevel@tonic-gate 		LE_64(efi_parts[i].efi_gpe_StartingLBA);
467*7c478bd9Sstevel@tonic-gate 	    vtoc->efi_parts[i].p_size =
468*7c478bd9Sstevel@tonic-gate 		LE_64(efi_parts[i].efi_gpe_EndingLBA) -
469*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_parts[i].p_start + 1;
470*7c478bd9Sstevel@tonic-gate 	    for (j = 0; j < EFI_PART_NAME_LEN; j++) {
471*7c478bd9Sstevel@tonic-gate 		vtoc->efi_parts[i].p_name[j] =
472*7c478bd9Sstevel@tonic-gate 		    (uchar_t)LE_16(efi_parts[i].efi_gpe_PartitionName[j]);
473*7c478bd9Sstevel@tonic-gate 	    }
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
476*7c478bd9Sstevel@tonic-gate 		efi_parts[i].efi_gpe_UniquePartitionGUID);
477*7c478bd9Sstevel@tonic-gate 	}
478*7c478bd9Sstevel@tonic-gate 	free(efi);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	return (dki_info.dki_partition);
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate /* writes a "protective" MBR */
484*7c478bd9Sstevel@tonic-gate static int
485*7c478bd9Sstevel@tonic-gate write_pmbr(int fd, struct dk_gpt *vtoc)
486*7c478bd9Sstevel@tonic-gate {
487*7c478bd9Sstevel@tonic-gate 	dk_efi_t	dk_ioc;
488*7c478bd9Sstevel@tonic-gate 	struct mboot	mb;
489*7c478bd9Sstevel@tonic-gate 	uchar_t		*cp;
490*7c478bd9Sstevel@tonic-gate 	diskaddr_t	size_in_lba;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	mb.signature = LE_16(MBB_MAGIC);
493*7c478bd9Sstevel@tonic-gate 	bzero(&mb.parts, sizeof (mb.parts));
494*7c478bd9Sstevel@tonic-gate 	cp = (uchar_t *)&mb.parts[0];
495*7c478bd9Sstevel@tonic-gate 	/* bootable or not */
496*7c478bd9Sstevel@tonic-gate 	*cp++ = 0;
497*7c478bd9Sstevel@tonic-gate 	/* beginning CHS; 0xffffff if not representable */
498*7c478bd9Sstevel@tonic-gate 	*cp++ = 0xff;
499*7c478bd9Sstevel@tonic-gate 	*cp++ = 0xff;
500*7c478bd9Sstevel@tonic-gate 	*cp++ = 0xff;
501*7c478bd9Sstevel@tonic-gate 	/* OS type */
502*7c478bd9Sstevel@tonic-gate 	*cp++ = EFI_PMBR;
503*7c478bd9Sstevel@tonic-gate 	/* ending CHS; 0xffffff if not representable */
504*7c478bd9Sstevel@tonic-gate 	*cp++ = 0xff;
505*7c478bd9Sstevel@tonic-gate 	*cp++ = 0xff;
506*7c478bd9Sstevel@tonic-gate 	*cp++ = 0xff;
507*7c478bd9Sstevel@tonic-gate 	/* starting LBA: 1 (little endian format) by EFI definition */
508*7c478bd9Sstevel@tonic-gate 	*cp++ = 0x01;
509*7c478bd9Sstevel@tonic-gate 	*cp++ = 0x00;
510*7c478bd9Sstevel@tonic-gate 	*cp++ = 0x00;
511*7c478bd9Sstevel@tonic-gate 	*cp++ = 0x00;
512*7c478bd9Sstevel@tonic-gate 	/* ending LBA: last block on the disk (little endian format) */
513*7c478bd9Sstevel@tonic-gate 	size_in_lba = vtoc->efi_last_lba;
514*7c478bd9Sstevel@tonic-gate 	if (size_in_lba < 0xffffffff) {
515*7c478bd9Sstevel@tonic-gate 		*cp++ = (size_in_lba & 0x000000ff);
516*7c478bd9Sstevel@tonic-gate 		*cp++ = (size_in_lba & 0x0000ff00) >> 8;
517*7c478bd9Sstevel@tonic-gate 		*cp++ = (size_in_lba & 0x00ff0000) >> 16;
518*7c478bd9Sstevel@tonic-gate 		*cp++ = (size_in_lba & 0xff000000) >> 24;
519*7c478bd9Sstevel@tonic-gate 	} else {
520*7c478bd9Sstevel@tonic-gate 		*cp++ = 0xff;
521*7c478bd9Sstevel@tonic-gate 		*cp++ = 0xff;
522*7c478bd9Sstevel@tonic-gate 		*cp++ = 0xff;
523*7c478bd9Sstevel@tonic-gate 		*cp++ = 0xff;
524*7c478bd9Sstevel@tonic-gate 	}
525*7c478bd9Sstevel@tonic-gate 	/* LINTED -- always longlong aligned */
526*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_data = (efi_gpt_t *)&mb;
527*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_lba = 0;
528*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_length = sizeof (mb);
529*7c478bd9Sstevel@tonic-gate 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
530*7c478bd9Sstevel@tonic-gate 		switch (errno) {
531*7c478bd9Sstevel@tonic-gate 		case EIO:
532*7c478bd9Sstevel@tonic-gate 			return (VT_EIO);
533*7c478bd9Sstevel@tonic-gate 		case EINVAL:
534*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
535*7c478bd9Sstevel@tonic-gate 		default:
536*7c478bd9Sstevel@tonic-gate 			return (VT_ERROR);
537*7c478bd9Sstevel@tonic-gate 		}
538*7c478bd9Sstevel@tonic-gate 	}
539*7c478bd9Sstevel@tonic-gate 	return (0);
540*7c478bd9Sstevel@tonic-gate }
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate /* make sure the user specified something reasonable */
543*7c478bd9Sstevel@tonic-gate static int
544*7c478bd9Sstevel@tonic-gate check_input(struct dk_gpt *vtoc)
545*7c478bd9Sstevel@tonic-gate {
546*7c478bd9Sstevel@tonic-gate 	int			resv_part = -1;
547*7c478bd9Sstevel@tonic-gate 	int			i, j;
548*7c478bd9Sstevel@tonic-gate 	diskaddr_t		istart, jstart, isize, jsize, endsect;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	/*
551*7c478bd9Sstevel@tonic-gate 	 * Sanity-check the input (make sure no partitions overlap)
552*7c478bd9Sstevel@tonic-gate 	 */
553*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < vtoc->efi_nparts; i++) {
554*7c478bd9Sstevel@tonic-gate 		/* It can't be unassigned and have an actual size */
555*7c478bd9Sstevel@tonic-gate 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
556*7c478bd9Sstevel@tonic-gate 		    (vtoc->efi_parts[i].p_size != 0)) {
557*7c478bd9Sstevel@tonic-gate 			if (efi_debug) {
558*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
559*7c478bd9Sstevel@tonic-gate "partition %d is \"unassigned\" but has a size of %llu",
560*7c478bd9Sstevel@tonic-gate 				    i,
561*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_parts[i].p_size);
562*7c478bd9Sstevel@tonic-gate 			}
563*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
566*7c478bd9Sstevel@tonic-gate 			continue;
567*7c478bd9Sstevel@tonic-gate 		}
568*7c478bd9Sstevel@tonic-gate 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
569*7c478bd9Sstevel@tonic-gate 			if (resv_part != -1) {
570*7c478bd9Sstevel@tonic-gate 				if (efi_debug) {
571*7c478bd9Sstevel@tonic-gate 				    (void) fprintf(stderr,
572*7c478bd9Sstevel@tonic-gate "found duplicate reserved partition at %d\n",
573*7c478bd9Sstevel@tonic-gate 					i);
574*7c478bd9Sstevel@tonic-gate 				}
575*7c478bd9Sstevel@tonic-gate 				return (VT_EINVAL);
576*7c478bd9Sstevel@tonic-gate 			}
577*7c478bd9Sstevel@tonic-gate 			resv_part = i;
578*7c478bd9Sstevel@tonic-gate 		}
579*7c478bd9Sstevel@tonic-gate 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
580*7c478bd9Sstevel@tonic-gate 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
581*7c478bd9Sstevel@tonic-gate 			if (efi_debug) {
582*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
583*7c478bd9Sstevel@tonic-gate 				    "Partition %d starts at %llu.  ",
584*7c478bd9Sstevel@tonic-gate 				    i,
585*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_parts[i].p_start);
586*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
587*7c478bd9Sstevel@tonic-gate 				    "It must be between %llu and %llu.\n",
588*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_first_u_lba,
589*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_last_u_lba);
590*7c478bd9Sstevel@tonic-gate 			}
591*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
592*7c478bd9Sstevel@tonic-gate 		}
593*7c478bd9Sstevel@tonic-gate 		if ((vtoc->efi_parts[i].p_start +
594*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_parts[i].p_size <
595*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_first_u_lba) ||
596*7c478bd9Sstevel@tonic-gate 		    (vtoc->efi_parts[i].p_start +
597*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_parts[i].p_size >
598*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_last_u_lba + 1)) {
599*7c478bd9Sstevel@tonic-gate 			if (efi_debug) {
600*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
601*7c478bd9Sstevel@tonic-gate 				    "Partition %d ends at %llu.  ",
602*7c478bd9Sstevel@tonic-gate 				    i,
603*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_parts[i].p_start +
604*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_parts[i].p_size);
605*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
606*7c478bd9Sstevel@tonic-gate 				    "It must be between %llu and %llu.\n",
607*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_first_u_lba,
608*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_last_u_lba);
609*7c478bd9Sstevel@tonic-gate 			}
610*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
611*7c478bd9Sstevel@tonic-gate 		}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < vtoc->efi_nparts; j++) {
614*7c478bd9Sstevel@tonic-gate 			isize = vtoc->efi_parts[i].p_size;
615*7c478bd9Sstevel@tonic-gate 			jsize = vtoc->efi_parts[j].p_size;
616*7c478bd9Sstevel@tonic-gate 			istart = vtoc->efi_parts[i].p_start;
617*7c478bd9Sstevel@tonic-gate 			jstart = vtoc->efi_parts[j].p_start;
618*7c478bd9Sstevel@tonic-gate 			if ((i != j) && (isize != 0) && (jsize != 0)) {
619*7c478bd9Sstevel@tonic-gate 				endsect = jstart + jsize -1;
620*7c478bd9Sstevel@tonic-gate 				if ((jstart <= istart) &&
621*7c478bd9Sstevel@tonic-gate 				    (istart <= endsect)) {
622*7c478bd9Sstevel@tonic-gate 					if (efi_debug) {
623*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
624*7c478bd9Sstevel@tonic-gate "Partition %d overlaps partition %d.",
625*7c478bd9Sstevel@tonic-gate 						    i, j);
626*7c478bd9Sstevel@tonic-gate 					    }
627*7c478bd9Sstevel@tonic-gate 					    return (VT_EINVAL);
628*7c478bd9Sstevel@tonic-gate 				}
629*7c478bd9Sstevel@tonic-gate 			}
630*7c478bd9Sstevel@tonic-gate 		}
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate 	/* just a warning for now */
633*7c478bd9Sstevel@tonic-gate 	if ((resv_part == -1) && efi_debug) {
634*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
635*7c478bd9Sstevel@tonic-gate 				"no reserved partition found\n");
636*7c478bd9Sstevel@tonic-gate 	}
637*7c478bd9Sstevel@tonic-gate 	return (0);
638*7c478bd9Sstevel@tonic-gate }
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate /*
641*7c478bd9Sstevel@tonic-gate  * write EFI label and backup label
642*7c478bd9Sstevel@tonic-gate  */
643*7c478bd9Sstevel@tonic-gate int
644*7c478bd9Sstevel@tonic-gate efi_write(int fd, struct dk_gpt *vtoc)
645*7c478bd9Sstevel@tonic-gate {
646*7c478bd9Sstevel@tonic-gate 	dk_efi_t		dk_ioc;
647*7c478bd9Sstevel@tonic-gate 	efi_gpt_t		*efi;
648*7c478bd9Sstevel@tonic-gate 	efi_gpe_t		*efi_parts;
649*7c478bd9Sstevel@tonic-gate 	int			i, j;
650*7c478bd9Sstevel@tonic-gate 	struct dk_cinfo		dki_info;
651*7c478bd9Sstevel@tonic-gate 	int			md_flag = 0;
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
654*7c478bd9Sstevel@tonic-gate 		if (efi_debug)
655*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
656*7c478bd9Sstevel@tonic-gate 		switch (errno) {
657*7c478bd9Sstevel@tonic-gate 		case EIO:
658*7c478bd9Sstevel@tonic-gate 			return (VT_EIO);
659*7c478bd9Sstevel@tonic-gate 		case EINVAL:
660*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
661*7c478bd9Sstevel@tonic-gate 		default:
662*7c478bd9Sstevel@tonic-gate 			return (VT_ERROR);
663*7c478bd9Sstevel@tonic-gate 		}
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	/* check if we are dealing wih a metadevice */
667*7c478bd9Sstevel@tonic-gate 	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
668*7c478bd9Sstevel@tonic-gate 	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
669*7c478bd9Sstevel@tonic-gate 		md_flag = 1;
670*7c478bd9Sstevel@tonic-gate 	}
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	if (check_input(vtoc)) {
673*7c478bd9Sstevel@tonic-gate 		/*
674*7c478bd9Sstevel@tonic-gate 		 * not valid; if it's a metadevice just pass it down
675*7c478bd9Sstevel@tonic-gate 		 * because SVM will do its own checking
676*7c478bd9Sstevel@tonic-gate 		 */
677*7c478bd9Sstevel@tonic-gate 		if (md_flag == 0) {
678*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
679*7c478bd9Sstevel@tonic-gate 		}
680*7c478bd9Sstevel@tonic-gate 	}
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_lba = 1;
683*7c478bd9Sstevel@tonic-gate 	if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
684*7c478bd9Sstevel@tonic-gate 		dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
685*7c478bd9Sstevel@tonic-gate 	} else {
686*7c478bd9Sstevel@tonic-gate 		dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
687*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_lbasize) *
688*7c478bd9Sstevel@tonic-gate 				    vtoc->efi_lbasize;
689*7c478bd9Sstevel@tonic-gate 	}
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL)
692*7c478bd9Sstevel@tonic-gate 		return (VT_ERROR);
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	efi = dk_ioc.dki_data;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	/* stuff user's input into EFI struct */
697*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
698*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
699*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
700*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_Reserved1 = 0;
701*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_MyLBA = LE_64(1ULL);
702*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_AlternateLBA = LE_64(vtoc->efi_last_lba);
703*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
704*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
705*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
706*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
707*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
708*7c478bd9Sstevel@tonic-gate 	UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	/* LINTED -- always longlong aligned */
711*7c478bd9Sstevel@tonic-gate 	efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + sizeof (efi_gpt_t));
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < vtoc->efi_nparts; i++) {
714*7c478bd9Sstevel@tonic-gate 	    for (j = 0;
715*7c478bd9Sstevel@tonic-gate 		j < sizeof (conversion_array) / sizeof (struct uuid_to_ptag);
716*7c478bd9Sstevel@tonic-gate 		j++) {
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 		    if (vtoc->efi_parts[i].p_tag == j) {
719*7c478bd9Sstevel@tonic-gate 			    UUID_LE_CONVERT(
720*7c478bd9Sstevel@tonic-gate 				efi_parts[i].efi_gpe_PartitionTypeGUID,
721*7c478bd9Sstevel@tonic-gate 				conversion_array[j].uuid);
722*7c478bd9Sstevel@tonic-gate 		    }
723*7c478bd9Sstevel@tonic-gate 	    }
724*7c478bd9Sstevel@tonic-gate 	    efi_parts[i].efi_gpe_StartingLBA =
725*7c478bd9Sstevel@tonic-gate 		LE_64(vtoc->efi_parts[i].p_start);
726*7c478bd9Sstevel@tonic-gate 	    efi_parts[i].efi_gpe_EndingLBA =
727*7c478bd9Sstevel@tonic-gate 		LE_64(vtoc->efi_parts[i].p_start +
728*7c478bd9Sstevel@tonic-gate 		vtoc->efi_parts[i].p_size - 1);
729*7c478bd9Sstevel@tonic-gate 	    efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
730*7c478bd9Sstevel@tonic-gate 		    LE_16(vtoc->efi_parts[i].p_flag);
731*7c478bd9Sstevel@tonic-gate 	    for (j = 0; j < EFI_PART_NAME_LEN; j++) {
732*7c478bd9Sstevel@tonic-gate 		    efi_parts[i].efi_gpe_PartitionName[j] =
733*7c478bd9Sstevel@tonic-gate 			LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
734*7c478bd9Sstevel@tonic-gate 	    }
735*7c478bd9Sstevel@tonic-gate 	    if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
736*7c478bd9Sstevel@tonic-gate 		uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
737*7c478bd9Sstevel@tonic-gate 		    (void) uuid_generate((uchar_t *)
738*7c478bd9Sstevel@tonic-gate 			&vtoc->efi_parts[i].p_uguid);
739*7c478bd9Sstevel@tonic-gate 	    }
740*7c478bd9Sstevel@tonic-gate 	    bcopy(&vtoc->efi_parts[i].p_uguid,
741*7c478bd9Sstevel@tonic-gate 		&efi_parts[i].efi_gpe_UniquePartitionGUID,
742*7c478bd9Sstevel@tonic-gate 		sizeof (uuid_t));
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_PartitionEntryArrayCRC32 =
745*7c478bd9Sstevel@tonic-gate 	    LE_32(efi_crc32((unsigned char *)efi_parts,
746*7c478bd9Sstevel@tonic-gate 	    vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
747*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_HeaderCRC32 =
748*7c478bd9Sstevel@tonic-gate 	    LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
751*7c478bd9Sstevel@tonic-gate 		free(dk_ioc.dki_data);
752*7c478bd9Sstevel@tonic-gate 		switch (errno) {
753*7c478bd9Sstevel@tonic-gate 		case EIO:
754*7c478bd9Sstevel@tonic-gate 			return (VT_EIO);
755*7c478bd9Sstevel@tonic-gate 		case EINVAL:
756*7c478bd9Sstevel@tonic-gate 			return (VT_EINVAL);
757*7c478bd9Sstevel@tonic-gate 		default:
758*7c478bd9Sstevel@tonic-gate 			return (VT_ERROR);
759*7c478bd9Sstevel@tonic-gate 		}
760*7c478bd9Sstevel@tonic-gate 	}
761*7c478bd9Sstevel@tonic-gate 	/* if it's a metadevice we're done */
762*7c478bd9Sstevel@tonic-gate 	if (md_flag) {
763*7c478bd9Sstevel@tonic-gate 		free(dk_ioc.dki_data);
764*7c478bd9Sstevel@tonic-gate 		return (0);
765*7c478bd9Sstevel@tonic-gate 	}
766*7c478bd9Sstevel@tonic-gate 	/* write backup partition array */
767*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
768*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_length -= vtoc->efi_lbasize;
769*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_data++;
770*7c478bd9Sstevel@tonic-gate 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
771*7c478bd9Sstevel@tonic-gate 		/*
772*7c478bd9Sstevel@tonic-gate 		 * we wrote the primary label okay, so don't fail
773*7c478bd9Sstevel@tonic-gate 		 */
774*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
775*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
776*7c478bd9Sstevel@tonic-gate 			    "write of backup partitions to block %llu "
777*7c478bd9Sstevel@tonic-gate 			    "failed, errno %d\n",
778*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_last_u_lba + 1,
779*7c478bd9Sstevel@tonic-gate 			    errno);
780*7c478bd9Sstevel@tonic-gate 		}
781*7c478bd9Sstevel@tonic-gate 	}
782*7c478bd9Sstevel@tonic-gate 	/*
783*7c478bd9Sstevel@tonic-gate 	 * now swap MyLBA and AlternateLBA fields and write backup
784*7c478bd9Sstevel@tonic-gate 	 * partition table header
785*7c478bd9Sstevel@tonic-gate 	 */
786*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_lba = vtoc->efi_last_lba;
787*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_length = vtoc->efi_lbasize;
788*7c478bd9Sstevel@tonic-gate 	dk_ioc.dki_data--;
789*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_AlternateLBA = LE_64(1ULL);
790*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_MyLBA = LE_64(vtoc->efi_last_lba);
791*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
792*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_HeaderCRC32 = 0;
793*7c478bd9Sstevel@tonic-gate 	efi->efi_gpt_HeaderCRC32 =
794*7c478bd9Sstevel@tonic-gate 	    LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
795*7c478bd9Sstevel@tonic-gate 	    sizeof (struct efi_gpt)));
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
798*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
799*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
800*7c478bd9Sstevel@tonic-gate 			    "write of backup header to block %llu failed, "
801*7c478bd9Sstevel@tonic-gate 			    "errno %d\n",
802*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_last_lba,
803*7c478bd9Sstevel@tonic-gate 			    errno);
804*7c478bd9Sstevel@tonic-gate 		}
805*7c478bd9Sstevel@tonic-gate 	}
806*7c478bd9Sstevel@tonic-gate 	/* write the PMBR */
807*7c478bd9Sstevel@tonic-gate 	(void) write_pmbr(fd, vtoc);
808*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, MHIOCREREGISTERDEVID) == -1) {
809*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
810*7c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr,
811*7c478bd9Sstevel@tonic-gate 			    "MHIOCREREGISTERDEVID failed %d\n",
812*7c478bd9Sstevel@tonic-gate 			    errno);
813*7c478bd9Sstevel@tonic-gate 		}
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 	free(dk_ioc.dki_data);
816*7c478bd9Sstevel@tonic-gate 	return (0);
817*7c478bd9Sstevel@tonic-gate }
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate void
820*7c478bd9Sstevel@tonic-gate efi_free(struct dk_gpt *ptr)
821*7c478bd9Sstevel@tonic-gate {
822*7c478bd9Sstevel@tonic-gate 	free(ptr);
823*7c478bd9Sstevel@tonic-gate }
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate /*
826*7c478bd9Sstevel@tonic-gate  * Input: File descriptor
827*7c478bd9Sstevel@tonic-gate  * Output: 1 if disk is >1TB OR has an EFI label, 0 otherwise.
828*7c478bd9Sstevel@tonic-gate  */
829*7c478bd9Sstevel@tonic-gate int
830*7c478bd9Sstevel@tonic-gate efi_type(int fd)
831*7c478bd9Sstevel@tonic-gate {
832*7c478bd9Sstevel@tonic-gate 	struct vtoc vtoc;
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1) {
835*7c478bd9Sstevel@tonic-gate 		if (errno == ENOTSUP) {
836*7c478bd9Sstevel@tonic-gate 			return (1);
837*7c478bd9Sstevel@tonic-gate 		}
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 	return (0);
840*7c478bd9Sstevel@tonic-gate }
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate void
843*7c478bd9Sstevel@tonic-gate efi_err_check(struct dk_gpt *vtoc)
844*7c478bd9Sstevel@tonic-gate {
845*7c478bd9Sstevel@tonic-gate 	int			resv_part = -1;
846*7c478bd9Sstevel@tonic-gate 	int			i, j;
847*7c478bd9Sstevel@tonic-gate 	diskaddr_t		istart, jstart, isize, jsize, endsect;
848*7c478bd9Sstevel@tonic-gate 	int			overlap = 0;
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	/*
851*7c478bd9Sstevel@tonic-gate 	 * make sure no partitions overlap
852*7c478bd9Sstevel@tonic-gate 	 */
853*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < vtoc->efi_nparts; i++) {
854*7c478bd9Sstevel@tonic-gate 		/* It can't be unassigned and have an actual size */
855*7c478bd9Sstevel@tonic-gate 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
856*7c478bd9Sstevel@tonic-gate 		    (vtoc->efi_parts[i].p_size != 0)) {
857*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
858*7c478bd9Sstevel@tonic-gate 			    "partition %d is \"unassigned\" but has a size "
859*7c478bd9Sstevel@tonic-gate 			    "of %llu\n", i, vtoc->efi_parts[i].p_size);
860*7c478bd9Sstevel@tonic-gate 		}
861*7c478bd9Sstevel@tonic-gate 		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
862*7c478bd9Sstevel@tonic-gate 			continue;
863*7c478bd9Sstevel@tonic-gate 		}
864*7c478bd9Sstevel@tonic-gate 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
865*7c478bd9Sstevel@tonic-gate 			if (resv_part != -1) {
866*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
867*7c478bd9Sstevel@tonic-gate 				    "found duplicate reserved partition at "
868*7c478bd9Sstevel@tonic-gate 				    "%d\n", i);
869*7c478bd9Sstevel@tonic-gate 			}
870*7c478bd9Sstevel@tonic-gate 			resv_part = i;
871*7c478bd9Sstevel@tonic-gate 			if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
872*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
873*7c478bd9Sstevel@tonic-gate 				    "Warning: reserved partition size must "
874*7c478bd9Sstevel@tonic-gate 				    "be %d sectors\n", EFI_MIN_RESV_SIZE);
875*7c478bd9Sstevel@tonic-gate 		}
876*7c478bd9Sstevel@tonic-gate 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
877*7c478bd9Sstevel@tonic-gate 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
878*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
879*7c478bd9Sstevel@tonic-gate 			    "Partition %d starts at %llu\n",
880*7c478bd9Sstevel@tonic-gate 			    i,
881*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_parts[i].p_start);
882*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
883*7c478bd9Sstevel@tonic-gate 			    "It must be between %llu and %llu.\n",
884*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_first_u_lba,
885*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_last_u_lba);
886*7c478bd9Sstevel@tonic-gate 		}
887*7c478bd9Sstevel@tonic-gate 		if ((vtoc->efi_parts[i].p_start +
888*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_parts[i].p_size <
889*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_first_u_lba) ||
890*7c478bd9Sstevel@tonic-gate 		    (vtoc->efi_parts[i].p_start +
891*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_parts[i].p_size >
892*7c478bd9Sstevel@tonic-gate 		    vtoc->efi_last_u_lba + 1)) {
893*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
894*7c478bd9Sstevel@tonic-gate 			    "Partition %d ends at %llu\n",
895*7c478bd9Sstevel@tonic-gate 			    i,
896*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_parts[i].p_start +
897*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_parts[i].p_size);
898*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
899*7c478bd9Sstevel@tonic-gate 			    "It must be between %llu and %llu.\n",
900*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_first_u_lba,
901*7c478bd9Sstevel@tonic-gate 			    vtoc->efi_last_u_lba);
902*7c478bd9Sstevel@tonic-gate 		}
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < vtoc->efi_nparts; j++) {
905*7c478bd9Sstevel@tonic-gate 			isize = vtoc->efi_parts[i].p_size;
906*7c478bd9Sstevel@tonic-gate 			jsize = vtoc->efi_parts[j].p_size;
907*7c478bd9Sstevel@tonic-gate 			istart = vtoc->efi_parts[i].p_start;
908*7c478bd9Sstevel@tonic-gate 			jstart = vtoc->efi_parts[j].p_start;
909*7c478bd9Sstevel@tonic-gate 			if ((i != j) && (isize != 0) && (jsize != 0)) {
910*7c478bd9Sstevel@tonic-gate 				endsect = jstart + jsize -1;
911*7c478bd9Sstevel@tonic-gate 				if ((jstart <= istart) &&
912*7c478bd9Sstevel@tonic-gate 				    (istart <= endsect)) {
913*7c478bd9Sstevel@tonic-gate 					if (!overlap) {
914*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
915*7c478bd9Sstevel@tonic-gate 					    "label error: EFI Labels do not "
916*7c478bd9Sstevel@tonic-gate 					    "support overlapping partitions\n");
917*7c478bd9Sstevel@tonic-gate 					}
918*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
919*7c478bd9Sstevel@tonic-gate 					    "Partition %d overlaps partition "
920*7c478bd9Sstevel@tonic-gate 					    "%d.\n", i, j);
921*7c478bd9Sstevel@tonic-gate 					overlap = 1;
922*7c478bd9Sstevel@tonic-gate 				}
923*7c478bd9Sstevel@tonic-gate 			}
924*7c478bd9Sstevel@tonic-gate 		}
925*7c478bd9Sstevel@tonic-gate 	}
926*7c478bd9Sstevel@tonic-gate 	/* make sure there is a reserved partition */
927*7c478bd9Sstevel@tonic-gate 	if (resv_part == -1) {
928*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
929*7c478bd9Sstevel@tonic-gate 			"no reserved partition found\n");
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate }
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate /*
934*7c478bd9Sstevel@tonic-gate  * We need to get information necessary to construct a *new* efi
935*7c478bd9Sstevel@tonic-gate  * label type
936*7c478bd9Sstevel@tonic-gate  */
937*7c478bd9Sstevel@tonic-gate int
938*7c478bd9Sstevel@tonic-gate efi_auto_sense(int fd, struct dk_gpt **vtoc)
939*7c478bd9Sstevel@tonic-gate {
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	int	i;
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	/*
944*7c478bd9Sstevel@tonic-gate 	 * Now build the default partition table
945*7c478bd9Sstevel@tonic-gate 	 */
946*7c478bd9Sstevel@tonic-gate 	if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
947*7c478bd9Sstevel@tonic-gate 		if (efi_debug) {
948*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "efi_alloc_and_init failed.\n");
949*7c478bd9Sstevel@tonic-gate 		}
950*7c478bd9Sstevel@tonic-gate 		return (-1);
951*7c478bd9Sstevel@tonic-gate 	}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
954*7c478bd9Sstevel@tonic-gate 		(*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
955*7c478bd9Sstevel@tonic-gate 		(*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
956*7c478bd9Sstevel@tonic-gate 		(*vtoc)->efi_parts[i].p_start = 0;
957*7c478bd9Sstevel@tonic-gate 		(*vtoc)->efi_parts[i].p_size = 0;
958*7c478bd9Sstevel@tonic-gate 	}
959*7c478bd9Sstevel@tonic-gate 	/*
960*7c478bd9Sstevel@tonic-gate 	 * Make constants first
961*7c478bd9Sstevel@tonic-gate 	 * and variable partitions later
962*7c478bd9Sstevel@tonic-gate 	 */
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	/* root partition - s0 128 MB */
965*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[0].p_start = 34;
966*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[0].p_size = 262144;
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	/* partition - s1  128 MB */
969*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[1].p_start = 262178;
970*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[1].p_size = 262144;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	/* partition -s2 is NOT the Backup disk */
973*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	/* partition -s6 /usr partition - HOG */
976*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[6].p_start = 524322;
977*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
978*7c478bd9Sstevel@tonic-gate 	    - (1024 * 16);
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	/* efi reserved partition - s9 16K */
981*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
982*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[8].p_size = (1024 * 16);
983*7c478bd9Sstevel@tonic-gate 	(*vtoc)->efi_parts[8].p_tag = V_RESERVED;
984*7c478bd9Sstevel@tonic-gate 	return (0);
985*7c478bd9Sstevel@tonic-gate }
986