xref: /illumos-gate/usr/src/uts/sun4v/io/vdsk_common.c (revision 4bac220845f606f60663ed6f3a2b88caa00ae87e)
1*4bac2208Snarayan /*
2*4bac2208Snarayan  * CDDL HEADER START
3*4bac2208Snarayan  *
4*4bac2208Snarayan  * The contents of this file are subject to the terms of the
5*4bac2208Snarayan  * Common Development and Distribution License (the "License").
6*4bac2208Snarayan  * You may not use this file except in compliance with the License.
7*4bac2208Snarayan  *
8*4bac2208Snarayan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4bac2208Snarayan  * or http://www.opensolaris.org/os/licensing.
10*4bac2208Snarayan  * See the License for the specific language governing permissions
11*4bac2208Snarayan  * and limitations under the License.
12*4bac2208Snarayan  *
13*4bac2208Snarayan  * When distributing Covered Code, include this CDDL HEADER in each
14*4bac2208Snarayan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4bac2208Snarayan  * If applicable, add the following below this CDDL HEADER, with the
16*4bac2208Snarayan  * fields enclosed by brackets "[]" replaced with your own identifying
17*4bac2208Snarayan  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4bac2208Snarayan  *
19*4bac2208Snarayan  * CDDL HEADER END
20*4bac2208Snarayan  */
21*4bac2208Snarayan 
22*4bac2208Snarayan /*
23*4bac2208Snarayan  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*4bac2208Snarayan  * Use is subject to license terms.
25*4bac2208Snarayan  */
26*4bac2208Snarayan 
27*4bac2208Snarayan #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*4bac2208Snarayan 
29*4bac2208Snarayan #include <sys/crc32.h>
30*4bac2208Snarayan #include <sys/cred.h>
31*4bac2208Snarayan #include <sys/ddi.h>
32*4bac2208Snarayan #include <sys/dkio.h>
33*4bac2208Snarayan #include <sys/file.h>
34*4bac2208Snarayan #include <sys/kmem.h>
35*4bac2208Snarayan #include <sys/sunddi.h>
36*4bac2208Snarayan #include <sys/sunldi.h>
37*4bac2208Snarayan #include <sys/types.h>
38*4bac2208Snarayan #include <sys/varargs.h>
39*4bac2208Snarayan #include <sys/vtoc.h>
40*4bac2208Snarayan 
41*4bac2208Snarayan #include <sys/vdsk_common.h>
42*4bac2208Snarayan 
43*4bac2208Snarayan /*
44*4bac2208Snarayan  * Hooks for EFI support
45*4bac2208Snarayan  */
46*4bac2208Snarayan 
47*4bac2208Snarayan /*
48*4bac2208Snarayan  * This code is a port of the functions efi_alloc_read() and efi_free() from
49*4bac2208Snarayan  * the libefi userland library to the kernel so that the vDisk drivers (vdc
50*4bac2208Snarayan  * and vds) can read EFI data. We will certaintly be able to remove that code
51*4bac2208Snarayan  * once RFE 6213117 is implemented.
52*4bac2208Snarayan  */
53*4bac2208Snarayan 
54*4bac2208Snarayan #define	VD_IOCTL_FLAGS  (FEXCL | FREAD | FWRITE | FKIOCTL)
55*4bac2208Snarayan 
56*4bac2208Snarayan #define	VD_EFI_DEBUG	if (vd_efi_debug) vd_efi_print
57*4bac2208Snarayan 
58*4bac2208Snarayan /*
59*4bac2208Snarayan  * The number of blocks the EFI label takes up (round up to nearest
60*4bac2208Snarayan  * block)
61*4bac2208Snarayan  */
62*4bac2208Snarayan #define	NBLOCKS(p, l)	(1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
63*4bac2208Snarayan 				((l) - 1)) / (l)))
64*4bac2208Snarayan /* number of partitions -- limited by what we can malloc */
65*4bac2208Snarayan #define	MAX_PARTS	((4294967295UL - sizeof (struct dk_gpt)) / \
66*4bac2208Snarayan 			    sizeof (struct dk_part))
67*4bac2208Snarayan 
68*4bac2208Snarayan /*
69*4bac2208Snarayan  * The vd_efi_alloc_and_read() function will use some ioctls to get EFI data
70*4bac2208Snarayan  * but the way we issue ioctl is different depending if we are on the vDisk
71*4bac2208Snarayan  * server side (vds) or on the vDisk client side.
72*4bac2208Snarayan  *
73*4bac2208Snarayan  * On the server side (vds), we reference a layered device (ldi_handle_t) so we
74*4bac2208Snarayan  * will use the LDI interface to execute ioctls (ldi_ioctl()). On the client
75*4bac2208Snarayan  * side (vdc), we reference a vdc device (with a dev_t) so we directly invoke
76*4bac2208Snarayan  * the function of the vdc driver implementing ioctls (vd_process_ioctl()).
77*4bac2208Snarayan  */
78*4bac2208Snarayan #define	VD_EFI_CALLER_VDS	0
79*4bac2208Snarayan #define	VD_EFI_CALLER_VDC	1
80*4bac2208Snarayan 
81*4bac2208Snarayan typedef struct vd_efi_dev {
82*4bac2208Snarayan 	int caller;
83*4bac2208Snarayan 	union {
84*4bac2208Snarayan 		ldi_handle_t vds;
85*4bac2208Snarayan 		dev_t vdc;
86*4bac2208Snarayan 	} ioctl_dev;
87*4bac2208Snarayan } vd_efi_dev_t;
88*4bac2208Snarayan 
89*4bac2208Snarayan static int (*vdc_ioctl_func)(dev_t dev, int cmd, caddr_t arg, int mode) = NULL;
90*4bac2208Snarayan 
91*4bac2208Snarayan static int vd_efi_debug = 1;
92*4bac2208Snarayan 
93*4bac2208Snarayan static struct uuid_to_ptag {
94*4bac2208Snarayan 	struct uuid	uuid;
95*4bac2208Snarayan } conversion_array[] = {
96*4bac2208Snarayan 	{ EFI_UNUSED },
97*4bac2208Snarayan 	{ EFI_BOOT },
98*4bac2208Snarayan 	{ EFI_ROOT },
99*4bac2208Snarayan 	{ EFI_SWAP },
100*4bac2208Snarayan 	{ EFI_USR },
101*4bac2208Snarayan 	{ EFI_BACKUP },
102*4bac2208Snarayan 	{ 0 },			/* STAND is never used */
103*4bac2208Snarayan 	{ EFI_VAR },
104*4bac2208Snarayan 	{ EFI_HOME },
105*4bac2208Snarayan 	{ EFI_ALTSCTR },
106*4bac2208Snarayan 	{ 0 },			/* CACHE (cachefs) is never used */
107*4bac2208Snarayan 	{ EFI_RESERVED },
108*4bac2208Snarayan 	{ EFI_SYSTEM },
109*4bac2208Snarayan 	{ EFI_LEGACY_MBR },
110*4bac2208Snarayan 	{ EFI_RESV3 },
111*4bac2208Snarayan 	{ EFI_RESV4 },
112*4bac2208Snarayan 	{ EFI_MSFT_RESV },
113*4bac2208Snarayan 	{ EFI_DELL_BASIC },
114*4bac2208Snarayan 	{ EFI_DELL_RAID },
115*4bac2208Snarayan 	{ EFI_DELL_SWAP },
116*4bac2208Snarayan 	{ EFI_DELL_LVM },
117*4bac2208Snarayan 	{ EFI_DELL_RESV }
118*4bac2208Snarayan };
119*4bac2208Snarayan 
120*4bac2208Snarayan static void
121*4bac2208Snarayan vd_efi_print(const char *format, ...)
122*4bac2208Snarayan {
123*4bac2208Snarayan 	va_list args;
124*4bac2208Snarayan 
125*4bac2208Snarayan 	va_start(args, format);
126*4bac2208Snarayan 	vcmn_err(CE_CONT, format, args);
127*4bac2208Snarayan 	va_end(args);
128*4bac2208Snarayan }
129*4bac2208Snarayan 
130*4bac2208Snarayan /*
131*4bac2208Snarayan  * Return a 32-bit CRC of the contents of the buffer.
132*4bac2208Snarayan  *
133*4bac2208Snarayan  * The seed is 0xffffffff and the result is XORed with 0xffffffff
134*4bac2208Snarayan  * because this is what the Itanium firmware expects.
135*4bac2208Snarayan  */
136*4bac2208Snarayan unsigned int
137*4bac2208Snarayan vd_efi_crc32(const unsigned char *s, unsigned int len)
138*4bac2208Snarayan {
139*4bac2208Snarayan 	unsigned int crc32val;
140*4bac2208Snarayan 
141*4bac2208Snarayan 	CRC32(crc32val, s, len, -1U, crc32_table);
142*4bac2208Snarayan 
143*4bac2208Snarayan 	return (crc32val ^ -1U);
144*4bac2208Snarayan }
145*4bac2208Snarayan 
146*4bac2208Snarayan static int
147*4bac2208Snarayan vd_ioctl(vd_efi_dev_t *dev, int cmd, void *arg, int flag,
148*4bac2208Snarayan     cred_t *cred, int *rvalp)
149*4bac2208Snarayan {
150*4bac2208Snarayan 	int error;
151*4bac2208Snarayan 
152*4bac2208Snarayan 	if (dev->caller == VD_EFI_CALLER_VDS) {
153*4bac2208Snarayan 		error = ldi_ioctl(dev->ioctl_dev.vds, cmd,
154*4bac2208Snarayan 		    (intptr_t)arg, flag, cred, rvalp);
155*4bac2208Snarayan 	} else {
156*4bac2208Snarayan 		ASSERT(vdc_ioctl_func != NULL);
157*4bac2208Snarayan 		error = (*vdc_ioctl_func)(dev->ioctl_dev.vdc, cmd,
158*4bac2208Snarayan 		    arg, flag);
159*4bac2208Snarayan 	}
160*4bac2208Snarayan 
161*4bac2208Snarayan 	return (error);
162*4bac2208Snarayan }
163*4bac2208Snarayan 
164*4bac2208Snarayan static int
165*4bac2208Snarayan vd_efi_ioctl(vd_efi_dev_t *dev, int cmd, dk_efi_t *dk_ioc)
166*4bac2208Snarayan {
167*4bac2208Snarayan 	void *data = dk_ioc->dki_data;
168*4bac2208Snarayan 	int error;
169*4bac2208Snarayan 
170*4bac2208Snarayan 	dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
171*4bac2208Snarayan 	error = vd_ioctl(dev, cmd, (caddr_t)dk_ioc, VD_IOCTL_FLAGS,
172*4bac2208Snarayan 	    kcred, NULL);
173*4bac2208Snarayan 	dk_ioc->dki_data = data;
174*4bac2208Snarayan 
175*4bac2208Snarayan 	return (error);
176*4bac2208Snarayan }
177*4bac2208Snarayan 
178*4bac2208Snarayan static int
179*4bac2208Snarayan vd_efi_check_label(vd_efi_dev_t *dev, dk_efi_t *dk_ioc)
180*4bac2208Snarayan {
181*4bac2208Snarayan 	efi_gpt_t *efi;
182*4bac2208Snarayan 	uint_t crc;
183*4bac2208Snarayan 	int status;
184*4bac2208Snarayan 
185*4bac2208Snarayan 	if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, dk_ioc)) != 0)
186*4bac2208Snarayan 		return (status);
187*4bac2208Snarayan 
188*4bac2208Snarayan 	efi = dk_ioc->dki_data;
189*4bac2208Snarayan 	if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
190*4bac2208Snarayan 		VD_EFI_DEBUG("Bad EFI signature: 0x%llx != 0x%llx\n",
191*4bac2208Snarayan 		    (long long)efi->efi_gpt_Signature,
192*4bac2208Snarayan 		    (long long)LE_64(EFI_SIGNATURE));
193*4bac2208Snarayan 		return (EINVAL);
194*4bac2208Snarayan 	}
195*4bac2208Snarayan 
196*4bac2208Snarayan 	/*
197*4bac2208Snarayan 	 * check CRC of the header; the size of the header should
198*4bac2208Snarayan 	 * never be larger than one block
199*4bac2208Snarayan 	 */
200*4bac2208Snarayan 	crc = efi->efi_gpt_HeaderCRC32;
201*4bac2208Snarayan 	efi->efi_gpt_HeaderCRC32 = 0;
202*4bac2208Snarayan 
203*4bac2208Snarayan 	if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
204*4bac2208Snarayan 	    crc != LE_32(vd_efi_crc32((unsigned char *)efi,
205*4bac2208Snarayan 	    LE_32(efi->efi_gpt_HeaderSize)))) {
206*4bac2208Snarayan 		VD_EFI_DEBUG("Bad EFI CRC: 0x%x != 0x%x\n",
207*4bac2208Snarayan 		    crc, LE_32(vd_efi_crc32((unsigned char *)efi,
208*4bac2208Snarayan 		    sizeof (struct efi_gpt))));
209*4bac2208Snarayan 		return (EINVAL);
210*4bac2208Snarayan 	}
211*4bac2208Snarayan 
212*4bac2208Snarayan 	return (0);
213*4bac2208Snarayan }
214*4bac2208Snarayan 
215*4bac2208Snarayan static int
216*4bac2208Snarayan vd_efi_read(vd_efi_dev_t *dev, struct dk_gpt *vtoc)
217*4bac2208Snarayan {
218*4bac2208Snarayan 	int			i, j, status;
219*4bac2208Snarayan 	int			label_len;
220*4bac2208Snarayan 	int			md_flag = 0;
221*4bac2208Snarayan 	struct dk_minfo		disk_info;
222*4bac2208Snarayan 	dk_efi_t		dk_ioc;
223*4bac2208Snarayan 	efi_gpt_t		*efi;
224*4bac2208Snarayan 	efi_gpe_t		*efi_parts;
225*4bac2208Snarayan 	struct dk_cinfo		dki_info;
226*4bac2208Snarayan 	uint32_t		user_length;
227*4bac2208Snarayan 
228*4bac2208Snarayan 	/*
229*4bac2208Snarayan 	 * get the partition number for this file descriptor.
230*4bac2208Snarayan 	 */
231*4bac2208Snarayan 	if ((status = vd_ioctl(dev, DKIOCINFO, &dki_info, VD_IOCTL_FLAGS,
232*4bac2208Snarayan 	    kcred, NULL)) != 0) {
233*4bac2208Snarayan 		VD_EFI_DEBUG("DKIOCINFO error 0x%x\n", status);
234*4bac2208Snarayan 		return (status);
235*4bac2208Snarayan 	}
236*4bac2208Snarayan 	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
237*4bac2208Snarayan 	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
238*4bac2208Snarayan 		md_flag++;
239*4bac2208Snarayan 	}
240*4bac2208Snarayan 	/* get the LBA size */
241*4bac2208Snarayan 	if ((status = vd_ioctl(dev, DKIOCGMEDIAINFO, &disk_info, VD_IOCTL_FLAGS,
242*4bac2208Snarayan 	    kcred, NULL)) != 0) {
243*4bac2208Snarayan 		VD_EFI_DEBUG("assuming LBA 512 bytes %d\n", status);
244*4bac2208Snarayan 		disk_info.dki_lbsize = DEV_BSIZE;
245*4bac2208Snarayan 	}
246*4bac2208Snarayan 	if (disk_info.dki_lbsize == 0) {
247*4bac2208Snarayan 		VD_EFI_DEBUG("efi_read: assuming LBA 512 bytes\n");
248*4bac2208Snarayan 		disk_info.dki_lbsize = DEV_BSIZE;
249*4bac2208Snarayan 	}
250*4bac2208Snarayan 	/*
251*4bac2208Snarayan 	 * Read the EFI GPT to figure out how many partitions we need
252*4bac2208Snarayan 	 * to deal with.
253*4bac2208Snarayan 	 */
254*4bac2208Snarayan 	dk_ioc.dki_lba = 1;
255*4bac2208Snarayan 	if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
256*4bac2208Snarayan 		label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
257*4bac2208Snarayan 	} else {
258*4bac2208Snarayan 		label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
259*4bac2208Snarayan 				    disk_info.dki_lbsize;
260*4bac2208Snarayan 		if (label_len % disk_info.dki_lbsize) {
261*4bac2208Snarayan 			/* pad to physical sector size */
262*4bac2208Snarayan 			label_len += disk_info.dki_lbsize;
263*4bac2208Snarayan 			label_len &= ~(disk_info.dki_lbsize - 1);
264*4bac2208Snarayan 		}
265*4bac2208Snarayan 	}
266*4bac2208Snarayan 
267*4bac2208Snarayan 	dk_ioc.dki_data = kmem_alloc(label_len, KM_SLEEP);
268*4bac2208Snarayan 	dk_ioc.dki_length = label_len;
269*4bac2208Snarayan 	user_length = vtoc->efi_nparts;
270*4bac2208Snarayan 	efi = dk_ioc.dki_data;
271*4bac2208Snarayan 	if (md_flag) {
272*4bac2208Snarayan 		if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_ioc)) != 0)
273*4bac2208Snarayan 			return (status);
274*4bac2208Snarayan 	} else if ((status = vd_efi_check_label(dev, &dk_ioc)) == EINVAL) {
275*4bac2208Snarayan 		/* no valid label here; try the alternate */
276*4bac2208Snarayan 		dk_ioc.dki_lba = disk_info.dki_capacity - 1;
277*4bac2208Snarayan 		dk_ioc.dki_length = disk_info.dki_lbsize;
278*4bac2208Snarayan 		if (vd_efi_check_label(dev, &dk_ioc) == 0) {
279*4bac2208Snarayan 			VD_EFI_DEBUG("efi_read: primary label corrupt; "
280*4bac2208Snarayan 			    "using backup\n");
281*4bac2208Snarayan 			dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
282*4bac2208Snarayan 			vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
283*4bac2208Snarayan 			vtoc->efi_nparts =
284*4bac2208Snarayan 			    LE_32(efi->efi_gpt_NumberOfPartitionEntries);
285*4bac2208Snarayan 			/*
286*4bac2208Snarayan 			 * partitions are between last usable LBA and
287*4bac2208Snarayan 			 * backup partition header
288*4bac2208Snarayan 			 */
289*4bac2208Snarayan 			dk_ioc.dki_data++;
290*4bac2208Snarayan 			dk_ioc.dki_length = disk_info.dki_capacity -
291*4bac2208Snarayan 						    dk_ioc.dki_lba - 1;
292*4bac2208Snarayan 			dk_ioc.dki_length *= disk_info.dki_lbsize;
293*4bac2208Snarayan 			if (dk_ioc.dki_length > (len_t)label_len) {
294*4bac2208Snarayan 				status = EINVAL;
295*4bac2208Snarayan 			} else {
296*4bac2208Snarayan 				status = vd_efi_ioctl(dev, DKIOCGETEFI,
297*4bac2208Snarayan 				    &dk_ioc);
298*4bac2208Snarayan 			}
299*4bac2208Snarayan 		}
300*4bac2208Snarayan 	}
301*4bac2208Snarayan 	if (status != 0) {
302*4bac2208Snarayan 		kmem_free(efi, label_len);
303*4bac2208Snarayan 		return (status);
304*4bac2208Snarayan 	}
305*4bac2208Snarayan 
306*4bac2208Snarayan 	/* partitions start in the next block */
307*4bac2208Snarayan 	/* LINTED -- always longlong aligned */
308*4bac2208Snarayan 	efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
309*4bac2208Snarayan 
310*4bac2208Snarayan 	/*
311*4bac2208Snarayan 	 * Assemble this into a "dk_gpt" struct for easier
312*4bac2208Snarayan 	 * digestibility by applications.
313*4bac2208Snarayan 	 */
314*4bac2208Snarayan 	vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
315*4bac2208Snarayan 	vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
316*4bac2208Snarayan 	vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
317*4bac2208Snarayan 	vtoc->efi_lbasize = disk_info.dki_lbsize;
318*4bac2208Snarayan 	vtoc->efi_last_lba = disk_info.dki_capacity - 1;
319*4bac2208Snarayan 	vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
320*4bac2208Snarayan 	vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
321*4bac2208Snarayan 	UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
322*4bac2208Snarayan 
323*4bac2208Snarayan 	/*
324*4bac2208Snarayan 	 * If the array the user passed in is too small, set the length
325*4bac2208Snarayan 	 * to what it needs to be and return
326*4bac2208Snarayan 	 */
327*4bac2208Snarayan 	if (user_length < vtoc->efi_nparts) {
328*4bac2208Snarayan 		kmem_free(efi, label_len);
329*4bac2208Snarayan 		return (EINVAL);
330*4bac2208Snarayan 	}
331*4bac2208Snarayan 
332*4bac2208Snarayan 	for (i = 0; i < vtoc->efi_nparts; i++) {
333*4bac2208Snarayan 
334*4bac2208Snarayan 	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
335*4bac2208Snarayan 		efi_parts[i].efi_gpe_PartitionTypeGUID);
336*4bac2208Snarayan 
337*4bac2208Snarayan 	    for (j = 0;
338*4bac2208Snarayan 		j < sizeof (conversion_array) / sizeof (struct uuid_to_ptag);
339*4bac2208Snarayan 		j++) {
340*4bac2208Snarayan 
341*4bac2208Snarayan 		    if (bcmp(&vtoc->efi_parts[i].p_guid,
342*4bac2208Snarayan 			&conversion_array[j].uuid,
343*4bac2208Snarayan 			sizeof (struct uuid)) == 0) {
344*4bac2208Snarayan 			    vtoc->efi_parts[i].p_tag = j;
345*4bac2208Snarayan 			    break;
346*4bac2208Snarayan 		    }
347*4bac2208Snarayan 	    }
348*4bac2208Snarayan 	    if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
349*4bac2208Snarayan 		    continue;
350*4bac2208Snarayan 	    vtoc->efi_parts[i].p_flag =
351*4bac2208Snarayan 		LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
352*4bac2208Snarayan 	    vtoc->efi_parts[i].p_start =
353*4bac2208Snarayan 		LE_64(efi_parts[i].efi_gpe_StartingLBA);
354*4bac2208Snarayan 	    vtoc->efi_parts[i].p_size =
355*4bac2208Snarayan 		LE_64(efi_parts[i].efi_gpe_EndingLBA) -
356*4bac2208Snarayan 		    vtoc->efi_parts[i].p_start + 1;
357*4bac2208Snarayan 	    for (j = 0; j < EFI_PART_NAME_LEN; j++) {
358*4bac2208Snarayan 		vtoc->efi_parts[i].p_name[j] =
359*4bac2208Snarayan 		    (uchar_t)LE_16(efi_parts[i].efi_gpe_PartitionName[j]);
360*4bac2208Snarayan 	    }
361*4bac2208Snarayan 
362*4bac2208Snarayan 	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
363*4bac2208Snarayan 		efi_parts[i].efi_gpe_UniquePartitionGUID);
364*4bac2208Snarayan 	}
365*4bac2208Snarayan 	kmem_free(efi, label_len);
366*4bac2208Snarayan 
367*4bac2208Snarayan 	return (0);
368*4bac2208Snarayan }
369*4bac2208Snarayan 
370*4bac2208Snarayan /*
371*4bac2208Snarayan  * Read EFI - return 0 upon success.
372*4bac2208Snarayan  */
373*4bac2208Snarayan static int
374*4bac2208Snarayan vd_efi_alloc_and_read(vd_efi_dev_t *dev, struct dk_gpt **vtoc, size_t *vtoc_len)
375*4bac2208Snarayan {
376*4bac2208Snarayan 	int status;
377*4bac2208Snarayan 	uint32_t nparts;
378*4bac2208Snarayan 	int length;
379*4bac2208Snarayan 
380*4bac2208Snarayan 	/* figure out the number of entries that would fit into 16K */
381*4bac2208Snarayan 	nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
382*4bac2208Snarayan 	length = (int) sizeof (struct dk_gpt) +
383*4bac2208Snarayan 	    (int) sizeof (struct dk_part) * (nparts - 1);
384*4bac2208Snarayan 
385*4bac2208Snarayan 	*vtoc = kmem_zalloc(length, KM_SLEEP);
386*4bac2208Snarayan 	(*vtoc)->efi_nparts = nparts;
387*4bac2208Snarayan 	status = vd_efi_read(dev, *vtoc);
388*4bac2208Snarayan 
389*4bac2208Snarayan 	if ((status == EINVAL) && (*vtoc)->efi_nparts > nparts) {
390*4bac2208Snarayan 		kmem_free(*vtoc, length);
391*4bac2208Snarayan 		length = (int) sizeof (struct dk_gpt) +
392*4bac2208Snarayan 				(int) sizeof (struct dk_part) *
393*4bac2208Snarayan 				((*vtoc)->efi_nparts - 1);
394*4bac2208Snarayan 		nparts = (*vtoc)->efi_nparts;
395*4bac2208Snarayan 		*vtoc = kmem_alloc(length, KM_SLEEP);
396*4bac2208Snarayan 		status = vd_efi_read(dev, *vtoc);
397*4bac2208Snarayan 	}
398*4bac2208Snarayan 
399*4bac2208Snarayan 	if (status != 0) {
400*4bac2208Snarayan 		VD_EFI_DEBUG("read of EFI table failed with error=%d\n",
401*4bac2208Snarayan 		    status);
402*4bac2208Snarayan 		kmem_free(*vtoc, length);
403*4bac2208Snarayan 		*vtoc = NULL;
404*4bac2208Snarayan 		*vtoc_len = 0;
405*4bac2208Snarayan 		return (status);
406*4bac2208Snarayan 	}
407*4bac2208Snarayan 
408*4bac2208Snarayan 	*vtoc_len = length;
409*4bac2208Snarayan 	return (0);
410*4bac2208Snarayan }
411*4bac2208Snarayan 
412*4bac2208Snarayan int
413*4bac2208Snarayan vdc_efi_alloc_and_read(dev_t dev, struct dk_gpt **vtoc, size_t *vtoc_len)
414*4bac2208Snarayan {
415*4bac2208Snarayan 	vd_efi_dev_t efi_dev;
416*4bac2208Snarayan 
417*4bac2208Snarayan 	ASSERT(vdc_ioctl_func != NULL);
418*4bac2208Snarayan 
419*4bac2208Snarayan 	efi_dev.caller = VD_EFI_CALLER_VDC;
420*4bac2208Snarayan 	efi_dev.ioctl_dev.vdc = dev;
421*4bac2208Snarayan 
422*4bac2208Snarayan 	return (vd_efi_alloc_and_read(&efi_dev, vtoc, vtoc_len));
423*4bac2208Snarayan }
424*4bac2208Snarayan 
425*4bac2208Snarayan int
426*4bac2208Snarayan vds_efi_alloc_and_read(ldi_handle_t dev, struct dk_gpt **vtoc, size_t *vtoc_len)
427*4bac2208Snarayan {
428*4bac2208Snarayan 	vd_efi_dev_t efi_dev;
429*4bac2208Snarayan 
430*4bac2208Snarayan 	efi_dev.caller = VD_EFI_CALLER_VDS;
431*4bac2208Snarayan 	efi_dev.ioctl_dev.vds = dev;
432*4bac2208Snarayan 
433*4bac2208Snarayan 	return (vd_efi_alloc_and_read(&efi_dev, vtoc, vtoc_len));
434*4bac2208Snarayan }
435*4bac2208Snarayan 
436*4bac2208Snarayan void
437*4bac2208Snarayan vd_efi_free(struct dk_gpt *ptr, size_t length)
438*4bac2208Snarayan {
439*4bac2208Snarayan 	kmem_free(ptr, length);
440*4bac2208Snarayan }
441*4bac2208Snarayan 
442*4bac2208Snarayan void
443*4bac2208Snarayan vdc_efi_init(int (*func)(dev_t, int, caddr_t, int))
444*4bac2208Snarayan {
445*4bac2208Snarayan 	vdc_ioctl_func = func;
446*4bac2208Snarayan }
447*4bac2208Snarayan 
448*4bac2208Snarayan void
449*4bac2208Snarayan vdc_efi_fini(void)
450*4bac2208Snarayan {
451*4bac2208Snarayan 	vdc_ioctl_func = NULL;
452*4bac2208Snarayan }
453*4bac2208Snarayan 
454*4bac2208Snarayan /*
455*4bac2208Snarayan  * This function stores EFI data (as returned by efi_alloc_and_read()) into
456*4bac2208Snarayan  * a vtoc structure. The vDisk driver uses a vtoc structure to store generic
457*4bac2208Snarayan  * information about disk partitions.
458*4bac2208Snarayan  */
459*4bac2208Snarayan void
460*4bac2208Snarayan vd_efi_to_vtoc(struct dk_gpt *efi, struct vtoc *vtoc)
461*4bac2208Snarayan {
462*4bac2208Snarayan 	int i, nparts;
463*4bac2208Snarayan 
464*4bac2208Snarayan 	bzero(vtoc, sizeof (struct vtoc));
465*4bac2208Snarayan 
466*4bac2208Snarayan 	vtoc->v_sanity = VTOC_SANE;
467*4bac2208Snarayan 
468*4bac2208Snarayan 	nparts = efi->efi_nparts;
469*4bac2208Snarayan 	for (i = 0; i < nparts; i++) {
470*4bac2208Snarayan 		if (efi->efi_parts[i].p_tag != V_RESERVED)
471*4bac2208Snarayan 			continue;
472*4bac2208Snarayan 		bcopy(efi->efi_parts[i].p_name, vtoc->v_volume,
473*4bac2208Snarayan 		    LEN_DKL_VVOL);
474*4bac2208Snarayan 		bcopy(efi->efi_parts[i].p_name, vtoc->v_asciilabel,
475*4bac2208Snarayan 		    EFI_PART_NAME_LEN);
476*4bac2208Snarayan 		break;
477*4bac2208Snarayan 	}
478*4bac2208Snarayan 
479*4bac2208Snarayan 	vtoc->v_sectorsz = efi->efi_lbasize;
480*4bac2208Snarayan 	vtoc->v_nparts = nparts;
481*4bac2208Snarayan 	for (i = 0; i < nparts; i++) {
482*4bac2208Snarayan 		/*
483*4bac2208Snarayan 		 * EFI can have more than 8 partitions. However the current
484*4bac2208Snarayan 		 * implementation of EFI on Solaris only support 7 partitions
485*4bac2208Snarayan 		 * (s0 to s6). There is no partition s7 but the minor number
486*4bac2208Snarayan 		 * corresponding to slice 7 is used to represent the whole
487*4bac2208Snarayan 		 * disk which data are stored in the "Sun Reserved" partition.
488*4bac2208Snarayan 		 * So we use the entry 7 of the vtoc structure to store
489*4bac2208Snarayan 		 * information about the whole disk.
490*4bac2208Snarayan 		 */
491*4bac2208Snarayan 		if (efi->efi_parts[i].p_tag == V_RESERVED) {
492*4bac2208Snarayan 			vtoc->v_part[VD_EFI_WD_SLICE].p_tag =
493*4bac2208Snarayan 				efi->efi_parts[i].p_tag;
494*4bac2208Snarayan 			vtoc->v_part[VD_EFI_WD_SLICE].p_flag =
495*4bac2208Snarayan 				efi->efi_parts[i].p_flag;
496*4bac2208Snarayan 			vtoc->v_part[VD_EFI_WD_SLICE].p_start =
497*4bac2208Snarayan 				efi->efi_parts[i].p_start;
498*4bac2208Snarayan 			vtoc->v_part[VD_EFI_WD_SLICE].p_size =
499*4bac2208Snarayan 				efi->efi_parts[i].p_size;
500*4bac2208Snarayan 			continue;
501*4bac2208Snarayan 		}
502*4bac2208Snarayan 
503*4bac2208Snarayan 		if (i >= VD_EFI_WD_SLICE) {
504*4bac2208Snarayan 			continue;
505*4bac2208Snarayan 		}
506*4bac2208Snarayan 
507*4bac2208Snarayan 		vtoc->v_part[i].p_tag = efi->efi_parts[i].p_tag;
508*4bac2208Snarayan 		if (efi->efi_parts[i].p_tag != V_UNASSIGNED) {
509*4bac2208Snarayan 			vtoc->v_part[i].p_flag = efi->efi_parts[i].p_flag;
510*4bac2208Snarayan 			vtoc->v_part[i].p_start = efi->efi_parts[i].p_start;
511*4bac2208Snarayan 			vtoc->v_part[i].p_size = efi->efi_parts[i].p_size;
512*4bac2208Snarayan 		}
513*4bac2208Snarayan 	}
514*4bac2208Snarayan }
515