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