1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6*eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7*eda14cbcSMatt Macy * 8*eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eda14cbcSMatt Macy * or http://www.opensolaris.org/os/licensing. 10*eda14cbcSMatt Macy * See the License for the specific language governing permissions 11*eda14cbcSMatt Macy * and limitations under the License. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14*eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16*eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17*eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18*eda14cbcSMatt Macy * 19*eda14cbcSMatt Macy * CDDL HEADER END 20*eda14cbcSMatt Macy */ 21*eda14cbcSMatt Macy 22*eda14cbcSMatt Macy /* 23*eda14cbcSMatt Macy * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 24*eda14cbcSMatt Macy * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 25*eda14cbcSMatt Macy * Copyright (c) 2018 by Delphix. All rights reserved. 26*eda14cbcSMatt Macy */ 27*eda14cbcSMatt Macy 28*eda14cbcSMatt Macy #include <stdio.h> 29*eda14cbcSMatt Macy #include <stdlib.h> 30*eda14cbcSMatt Macy #include <errno.h> 31*eda14cbcSMatt Macy #include <string.h> 32*eda14cbcSMatt Macy #include <strings.h> 33*eda14cbcSMatt Macy #include <unistd.h> 34*eda14cbcSMatt Macy #include <uuid/uuid.h> 35*eda14cbcSMatt Macy #include <zlib.h> 36*eda14cbcSMatt Macy #include <libintl.h> 37*eda14cbcSMatt Macy #include <sys/types.h> 38*eda14cbcSMatt Macy #include <sys/dkio.h> 39*eda14cbcSMatt Macy #include <sys/vtoc.h> 40*eda14cbcSMatt Macy #include <sys/mhd.h> 41*eda14cbcSMatt Macy #include <sys/param.h> 42*eda14cbcSMatt Macy #include <sys/dktp/fdisk.h> 43*eda14cbcSMatt Macy #include <sys/efi_partition.h> 44*eda14cbcSMatt Macy #include <sys/byteorder.h> 45*eda14cbcSMatt Macy #include <sys/vdev_disk.h> 46*eda14cbcSMatt Macy #include <linux/fs.h> 47*eda14cbcSMatt Macy 48*eda14cbcSMatt Macy static struct uuid_to_ptag { 49*eda14cbcSMatt Macy struct uuid uuid; 50*eda14cbcSMatt Macy } conversion_array[] = { 51*eda14cbcSMatt Macy { EFI_UNUSED }, 52*eda14cbcSMatt Macy { EFI_BOOT }, 53*eda14cbcSMatt Macy { EFI_ROOT }, 54*eda14cbcSMatt Macy { EFI_SWAP }, 55*eda14cbcSMatt Macy { EFI_USR }, 56*eda14cbcSMatt Macy { EFI_BACKUP }, 57*eda14cbcSMatt Macy { EFI_UNUSED }, /* STAND is never used */ 58*eda14cbcSMatt Macy { EFI_VAR }, 59*eda14cbcSMatt Macy { EFI_HOME }, 60*eda14cbcSMatt Macy { EFI_ALTSCTR }, 61*eda14cbcSMatt Macy { EFI_UNUSED }, /* CACHE (cachefs) is never used */ 62*eda14cbcSMatt Macy { EFI_RESERVED }, 63*eda14cbcSMatt Macy { EFI_SYSTEM }, 64*eda14cbcSMatt Macy { EFI_LEGACY_MBR }, 65*eda14cbcSMatt Macy { EFI_SYMC_PUB }, 66*eda14cbcSMatt Macy { EFI_SYMC_CDS }, 67*eda14cbcSMatt Macy { EFI_MSFT_RESV }, 68*eda14cbcSMatt Macy { EFI_DELL_BASIC }, 69*eda14cbcSMatt Macy { EFI_DELL_RAID }, 70*eda14cbcSMatt Macy { EFI_DELL_SWAP }, 71*eda14cbcSMatt Macy { EFI_DELL_LVM }, 72*eda14cbcSMatt Macy { EFI_DELL_RESV }, 73*eda14cbcSMatt Macy { EFI_AAPL_HFS }, 74*eda14cbcSMatt Macy { EFI_AAPL_UFS }, 75*eda14cbcSMatt Macy { EFI_FREEBSD_BOOT }, 76*eda14cbcSMatt Macy { EFI_FREEBSD_SWAP }, 77*eda14cbcSMatt Macy { EFI_FREEBSD_UFS }, 78*eda14cbcSMatt Macy { EFI_FREEBSD_VINUM }, 79*eda14cbcSMatt Macy { EFI_FREEBSD_ZFS }, 80*eda14cbcSMatt Macy { EFI_BIOS_BOOT }, 81*eda14cbcSMatt Macy { EFI_INTC_RS }, 82*eda14cbcSMatt Macy { EFI_SNE_BOOT }, 83*eda14cbcSMatt Macy { EFI_LENOVO_BOOT }, 84*eda14cbcSMatt Macy { EFI_MSFT_LDMM }, 85*eda14cbcSMatt Macy { EFI_MSFT_LDMD }, 86*eda14cbcSMatt Macy { EFI_MSFT_RE }, 87*eda14cbcSMatt Macy { EFI_IBM_GPFS }, 88*eda14cbcSMatt Macy { EFI_MSFT_STORAGESPACES }, 89*eda14cbcSMatt Macy { EFI_HPQ_DATA }, 90*eda14cbcSMatt Macy { EFI_HPQ_SVC }, 91*eda14cbcSMatt Macy { EFI_RHT_DATA }, 92*eda14cbcSMatt Macy { EFI_RHT_HOME }, 93*eda14cbcSMatt Macy { EFI_RHT_SRV }, 94*eda14cbcSMatt Macy { EFI_RHT_DMCRYPT }, 95*eda14cbcSMatt Macy { EFI_RHT_LUKS }, 96*eda14cbcSMatt Macy { EFI_FREEBSD_DISKLABEL }, 97*eda14cbcSMatt Macy { EFI_AAPL_RAID }, 98*eda14cbcSMatt Macy { EFI_AAPL_RAIDOFFLINE }, 99*eda14cbcSMatt Macy { EFI_AAPL_BOOT }, 100*eda14cbcSMatt Macy { EFI_AAPL_LABEL }, 101*eda14cbcSMatt Macy { EFI_AAPL_TVRECOVERY }, 102*eda14cbcSMatt Macy { EFI_AAPL_CORESTORAGE }, 103*eda14cbcSMatt Macy { EFI_NETBSD_SWAP }, 104*eda14cbcSMatt Macy { EFI_NETBSD_FFS }, 105*eda14cbcSMatt Macy { EFI_NETBSD_LFS }, 106*eda14cbcSMatt Macy { EFI_NETBSD_RAID }, 107*eda14cbcSMatt Macy { EFI_NETBSD_CAT }, 108*eda14cbcSMatt Macy { EFI_NETBSD_CRYPT }, 109*eda14cbcSMatt Macy { EFI_GOOG_KERN }, 110*eda14cbcSMatt Macy { EFI_GOOG_ROOT }, 111*eda14cbcSMatt Macy { EFI_GOOG_RESV }, 112*eda14cbcSMatt Macy { EFI_HAIKU_BFS }, 113*eda14cbcSMatt Macy { EFI_MIDNIGHTBSD_BOOT }, 114*eda14cbcSMatt Macy { EFI_MIDNIGHTBSD_DATA }, 115*eda14cbcSMatt Macy { EFI_MIDNIGHTBSD_SWAP }, 116*eda14cbcSMatt Macy { EFI_MIDNIGHTBSD_UFS }, 117*eda14cbcSMatt Macy { EFI_MIDNIGHTBSD_VINUM }, 118*eda14cbcSMatt Macy { EFI_MIDNIGHTBSD_ZFS }, 119*eda14cbcSMatt Macy { EFI_CEPH_JOURNAL }, 120*eda14cbcSMatt Macy { EFI_CEPH_DMCRYPTJOURNAL }, 121*eda14cbcSMatt Macy { EFI_CEPH_OSD }, 122*eda14cbcSMatt Macy { EFI_CEPH_DMCRYPTOSD }, 123*eda14cbcSMatt Macy { EFI_CEPH_CREATE }, 124*eda14cbcSMatt Macy { EFI_CEPH_DMCRYPTCREATE }, 125*eda14cbcSMatt Macy { EFI_OPENBSD_DISKLABEL }, 126*eda14cbcSMatt Macy { EFI_BBRY_QNX }, 127*eda14cbcSMatt Macy { EFI_BELL_PLAN9 }, 128*eda14cbcSMatt Macy { EFI_VMW_KCORE }, 129*eda14cbcSMatt Macy { EFI_VMW_VMFS }, 130*eda14cbcSMatt Macy { EFI_VMW_RESV }, 131*eda14cbcSMatt Macy { EFI_RHT_ROOTX86 }, 132*eda14cbcSMatt Macy { EFI_RHT_ROOTAMD64 }, 133*eda14cbcSMatt Macy { EFI_RHT_ROOTARM }, 134*eda14cbcSMatt Macy { EFI_RHT_ROOTARM64 }, 135*eda14cbcSMatt Macy { EFI_ACRONIS_SECUREZONE }, 136*eda14cbcSMatt Macy { EFI_ONIE_BOOT }, 137*eda14cbcSMatt Macy { EFI_ONIE_CONFIG }, 138*eda14cbcSMatt Macy { EFI_IBM_PPRPBOOT }, 139*eda14cbcSMatt Macy { EFI_FREEDESKTOP_BOOT } 140*eda14cbcSMatt Macy }; 141*eda14cbcSMatt Macy 142*eda14cbcSMatt Macy /* 143*eda14cbcSMatt Macy * Default vtoc information for non-SVr4 partitions 144*eda14cbcSMatt Macy */ 145*eda14cbcSMatt Macy struct dk_map2 default_vtoc_map[NDKMAP] = { 146*eda14cbcSMatt Macy { V_ROOT, 0 }, /* a - 0 */ 147*eda14cbcSMatt Macy { V_SWAP, V_UNMNT }, /* b - 1 */ 148*eda14cbcSMatt Macy { V_BACKUP, V_UNMNT }, /* c - 2 */ 149*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* d - 3 */ 150*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* e - 4 */ 151*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* f - 5 */ 152*eda14cbcSMatt Macy { V_USR, 0 }, /* g - 6 */ 153*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* h - 7 */ 154*eda14cbcSMatt Macy 155*eda14cbcSMatt Macy #if defined(_SUNOS_VTOC_16) 156*eda14cbcSMatt Macy 157*eda14cbcSMatt Macy #if defined(i386) || defined(__amd64) || defined(__arm) || \ 158*eda14cbcSMatt Macy defined(__powerpc) || defined(__sparc) || defined(__s390__) || \ 159*eda14cbcSMatt Macy defined(__mips__) || defined(__rv64g__) 160*eda14cbcSMatt Macy { V_BOOT, V_UNMNT }, /* i - 8 */ 161*eda14cbcSMatt Macy { V_ALTSCTR, 0 }, /* j - 9 */ 162*eda14cbcSMatt Macy 163*eda14cbcSMatt Macy #else 164*eda14cbcSMatt Macy #error No VTOC format defined. 165*eda14cbcSMatt Macy #endif /* defined(i386) */ 166*eda14cbcSMatt Macy 167*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* k - 10 */ 168*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* l - 11 */ 169*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* m - 12 */ 170*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* n - 13 */ 171*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* o - 14 */ 172*eda14cbcSMatt Macy { V_UNASSIGNED, 0 }, /* p - 15 */ 173*eda14cbcSMatt Macy #endif /* defined(_SUNOS_VTOC_16) */ 174*eda14cbcSMatt Macy }; 175*eda14cbcSMatt Macy 176*eda14cbcSMatt Macy int efi_debug = 0; 177*eda14cbcSMatt Macy 178*eda14cbcSMatt Macy static int efi_read(int, struct dk_gpt *); 179*eda14cbcSMatt Macy 180*eda14cbcSMatt Macy /* 181*eda14cbcSMatt Macy * Return a 32-bit CRC of the contents of the buffer. Pre-and-post 182*eda14cbcSMatt Macy * one's conditioning will be handled by crc32() internally. 183*eda14cbcSMatt Macy */ 184*eda14cbcSMatt Macy static uint32_t 185*eda14cbcSMatt Macy efi_crc32(const unsigned char *buf, unsigned int size) 186*eda14cbcSMatt Macy { 187*eda14cbcSMatt Macy uint32_t crc = crc32(0, Z_NULL, 0); 188*eda14cbcSMatt Macy 189*eda14cbcSMatt Macy crc = crc32(crc, buf, size); 190*eda14cbcSMatt Macy 191*eda14cbcSMatt Macy return (crc); 192*eda14cbcSMatt Macy } 193*eda14cbcSMatt Macy 194*eda14cbcSMatt Macy static int 195*eda14cbcSMatt Macy read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize) 196*eda14cbcSMatt Macy { 197*eda14cbcSMatt Macy int sector_size; 198*eda14cbcSMatt Macy unsigned long long capacity_size; 199*eda14cbcSMatt Macy 200*eda14cbcSMatt Macy if (ioctl(fd, BLKSSZGET, §or_size) < 0) 201*eda14cbcSMatt Macy return (-1); 202*eda14cbcSMatt Macy 203*eda14cbcSMatt Macy if (ioctl(fd, BLKGETSIZE64, &capacity_size) < 0) 204*eda14cbcSMatt Macy return (-1); 205*eda14cbcSMatt Macy 206*eda14cbcSMatt Macy *lbsize = (uint_t)sector_size; 207*eda14cbcSMatt Macy *capacity = (diskaddr_t)(capacity_size / sector_size); 208*eda14cbcSMatt Macy 209*eda14cbcSMatt Macy return (0); 210*eda14cbcSMatt Macy } 211*eda14cbcSMatt Macy 212*eda14cbcSMatt Macy static int 213*eda14cbcSMatt Macy efi_get_info(int fd, struct dk_cinfo *dki_info) 214*eda14cbcSMatt Macy { 215*eda14cbcSMatt Macy char *path; 216*eda14cbcSMatt Macy char *dev_path; 217*eda14cbcSMatt Macy int rval = 0; 218*eda14cbcSMatt Macy 219*eda14cbcSMatt Macy memset(dki_info, 0, sizeof (*dki_info)); 220*eda14cbcSMatt Macy 221*eda14cbcSMatt Macy path = calloc(1, PATH_MAX); 222*eda14cbcSMatt Macy if (path == NULL) 223*eda14cbcSMatt Macy goto error; 224*eda14cbcSMatt Macy 225*eda14cbcSMatt Macy /* 226*eda14cbcSMatt Macy * The simplest way to get the partition number under linux is 227*eda14cbcSMatt Macy * to parse it out of the /dev/<disk><partition> block device name. 228*eda14cbcSMatt Macy * The kernel creates this using the partition number when it 229*eda14cbcSMatt Macy * populates /dev/ so it may be trusted. The tricky bit here is 230*eda14cbcSMatt Macy * that the naming convention is based on the block device type. 231*eda14cbcSMatt Macy * So we need to take this in to account when parsing out the 232*eda14cbcSMatt Macy * partition information. Another issue is that the libefi API 233*eda14cbcSMatt Macy * API only provides the open fd and not the file path. To handle 234*eda14cbcSMatt Macy * this realpath(3) is used to resolve the block device name from 235*eda14cbcSMatt Macy * /proc/self/fd/<fd>. Aside from the partition number we collect 236*eda14cbcSMatt Macy * some additional device info. 237*eda14cbcSMatt Macy */ 238*eda14cbcSMatt Macy (void) sprintf(path, "/proc/self/fd/%d", fd); 239*eda14cbcSMatt Macy dev_path = realpath(path, NULL); 240*eda14cbcSMatt Macy free(path); 241*eda14cbcSMatt Macy 242*eda14cbcSMatt Macy if (dev_path == NULL) 243*eda14cbcSMatt Macy goto error; 244*eda14cbcSMatt Macy 245*eda14cbcSMatt Macy if ((strncmp(dev_path, "/dev/sd", 7) == 0)) { 246*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "sd"); 247*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_SCSI_CCS; 248*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu", 249*eda14cbcSMatt Macy dki_info->dki_dname, 250*eda14cbcSMatt Macy &dki_info->dki_partition); 251*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/hd", 7) == 0)) { 252*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "hd"); 253*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_DIRECT; 254*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu", 255*eda14cbcSMatt Macy dki_info->dki_dname, 256*eda14cbcSMatt Macy &dki_info->dki_partition); 257*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/md", 7) == 0)) { 258*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "pseudo"); 259*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_MD; 260*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "md"); 261*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/md%[0-9]p%hu", 262*eda14cbcSMatt Macy dki_info->dki_dname + 2, 263*eda14cbcSMatt Macy &dki_info->dki_partition); 264*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/vd", 7) == 0)) { 265*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "vd"); 266*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_MD; 267*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu", 268*eda14cbcSMatt Macy dki_info->dki_dname, 269*eda14cbcSMatt Macy &dki_info->dki_partition); 270*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/xvd", 8) == 0)) { 271*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "xvd"); 272*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_MD; 273*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu", 274*eda14cbcSMatt Macy dki_info->dki_dname, 275*eda14cbcSMatt Macy &dki_info->dki_partition); 276*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/zd", 7) == 0)) { 277*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "zd"); 278*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_MD; 279*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "zd"); 280*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/zd%[0-9]p%hu", 281*eda14cbcSMatt Macy dki_info->dki_dname + 2, 282*eda14cbcSMatt Macy &dki_info->dki_partition); 283*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/dm-", 8) == 0)) { 284*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "pseudo"); 285*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_VBD; 286*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "dm-"); 287*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/dm-%[0-9]p%hu", 288*eda14cbcSMatt Macy dki_info->dki_dname + 3, 289*eda14cbcSMatt Macy &dki_info->dki_partition); 290*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/ram", 8) == 0)) { 291*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "pseudo"); 292*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_PCMCIA_MEM; 293*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "ram"); 294*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/ram%[0-9]p%hu", 295*eda14cbcSMatt Macy dki_info->dki_dname + 3, 296*eda14cbcSMatt Macy &dki_info->dki_partition); 297*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/loop", 9) == 0)) { 298*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "pseudo"); 299*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_VBD; 300*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "loop"); 301*eda14cbcSMatt Macy rval = sscanf(dev_path, "/dev/loop%[0-9]p%hu", 302*eda14cbcSMatt Macy dki_info->dki_dname + 4, 303*eda14cbcSMatt Macy &dki_info->dki_partition); 304*eda14cbcSMatt Macy } else if ((strncmp(dev_path, "/dev/nvme", 9) == 0)) { 305*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "nvme"); 306*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_SCSI_CCS; 307*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "nvme"); 308*eda14cbcSMatt Macy (void) sscanf(dev_path, "/dev/nvme%[0-9]", 309*eda14cbcSMatt Macy dki_info->dki_dname + 4); 310*eda14cbcSMatt Macy size_t controller_length = strlen( 311*eda14cbcSMatt Macy dki_info->dki_dname); 312*eda14cbcSMatt Macy strcpy(dki_info->dki_dname + controller_length, 313*eda14cbcSMatt Macy "n"); 314*eda14cbcSMatt Macy rval = sscanf(dev_path, 315*eda14cbcSMatt Macy "/dev/nvme%*[0-9]n%[0-9]p%hu", 316*eda14cbcSMatt Macy dki_info->dki_dname + controller_length + 1, 317*eda14cbcSMatt Macy &dki_info->dki_partition); 318*eda14cbcSMatt Macy } else { 319*eda14cbcSMatt Macy strcpy(dki_info->dki_dname, "unknown"); 320*eda14cbcSMatt Macy strcpy(dki_info->dki_cname, "unknown"); 321*eda14cbcSMatt Macy dki_info->dki_ctype = DKC_UNKNOWN; 322*eda14cbcSMatt Macy } 323*eda14cbcSMatt Macy 324*eda14cbcSMatt Macy switch (rval) { 325*eda14cbcSMatt Macy case 0: 326*eda14cbcSMatt Macy errno = EINVAL; 327*eda14cbcSMatt Macy goto error; 328*eda14cbcSMatt Macy case 1: 329*eda14cbcSMatt Macy dki_info->dki_partition = 0; 330*eda14cbcSMatt Macy } 331*eda14cbcSMatt Macy 332*eda14cbcSMatt Macy free(dev_path); 333*eda14cbcSMatt Macy 334*eda14cbcSMatt Macy return (0); 335*eda14cbcSMatt Macy error: 336*eda14cbcSMatt Macy if (efi_debug) 337*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno); 338*eda14cbcSMatt Macy 339*eda14cbcSMatt Macy switch (errno) { 340*eda14cbcSMatt Macy case EIO: 341*eda14cbcSMatt Macy return (VT_EIO); 342*eda14cbcSMatt Macy case EINVAL: 343*eda14cbcSMatt Macy return (VT_EINVAL); 344*eda14cbcSMatt Macy default: 345*eda14cbcSMatt Macy return (VT_ERROR); 346*eda14cbcSMatt Macy } 347*eda14cbcSMatt Macy } 348*eda14cbcSMatt Macy 349*eda14cbcSMatt Macy /* 350*eda14cbcSMatt Macy * the number of blocks the EFI label takes up (round up to nearest 351*eda14cbcSMatt Macy * block) 352*eda14cbcSMatt Macy */ 353*eda14cbcSMatt Macy #define NBLOCKS(p, l) (1 + ((((p) * (int)sizeof (efi_gpe_t)) + \ 354*eda14cbcSMatt Macy ((l) - 1)) / (l))) 355*eda14cbcSMatt Macy /* number of partitions -- limited by what we can malloc */ 356*eda14cbcSMatt Macy #define MAX_PARTS ((4294967295UL - sizeof (struct dk_gpt)) / \ 357*eda14cbcSMatt Macy sizeof (struct dk_part)) 358*eda14cbcSMatt Macy 359*eda14cbcSMatt Macy int 360*eda14cbcSMatt Macy efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc) 361*eda14cbcSMatt Macy { 362*eda14cbcSMatt Macy diskaddr_t capacity = 0; 363*eda14cbcSMatt Macy uint_t lbsize = 0; 364*eda14cbcSMatt Macy uint_t nblocks; 365*eda14cbcSMatt Macy size_t length; 366*eda14cbcSMatt Macy struct dk_gpt *vptr; 367*eda14cbcSMatt Macy struct uuid uuid; 368*eda14cbcSMatt Macy struct dk_cinfo dki_info; 369*eda14cbcSMatt Macy 370*eda14cbcSMatt Macy if (read_disk_info(fd, &capacity, &lbsize) != 0) 371*eda14cbcSMatt Macy return (-1); 372*eda14cbcSMatt Macy 373*eda14cbcSMatt Macy if (efi_get_info(fd, &dki_info) != 0) 374*eda14cbcSMatt Macy return (-1); 375*eda14cbcSMatt Macy 376*eda14cbcSMatt Macy if (dki_info.dki_partition != 0) 377*eda14cbcSMatt Macy return (-1); 378*eda14cbcSMatt Macy 379*eda14cbcSMatt Macy if ((dki_info.dki_ctype == DKC_PCMCIA_MEM) || 380*eda14cbcSMatt Macy (dki_info.dki_ctype == DKC_VBD) || 381*eda14cbcSMatt Macy (dki_info.dki_ctype == DKC_UNKNOWN)) 382*eda14cbcSMatt Macy return (-1); 383*eda14cbcSMatt Macy 384*eda14cbcSMatt Macy nblocks = NBLOCKS(nparts, lbsize); 385*eda14cbcSMatt Macy if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) { 386*eda14cbcSMatt Macy /* 16K plus one block for the GPT */ 387*eda14cbcSMatt Macy nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1; 388*eda14cbcSMatt Macy } 389*eda14cbcSMatt Macy 390*eda14cbcSMatt Macy if (nparts > MAX_PARTS) { 391*eda14cbcSMatt Macy if (efi_debug) { 392*eda14cbcSMatt Macy (void) fprintf(stderr, 393*eda14cbcSMatt Macy "the maximum number of partitions supported is %lu\n", 394*eda14cbcSMatt Macy MAX_PARTS); 395*eda14cbcSMatt Macy } 396*eda14cbcSMatt Macy return (-1); 397*eda14cbcSMatt Macy } 398*eda14cbcSMatt Macy 399*eda14cbcSMatt Macy length = sizeof (struct dk_gpt) + 400*eda14cbcSMatt Macy sizeof (struct dk_part) * (nparts - 1); 401*eda14cbcSMatt Macy 402*eda14cbcSMatt Macy vptr = calloc(1, length); 403*eda14cbcSMatt Macy if (vptr == NULL) 404*eda14cbcSMatt Macy return (-1); 405*eda14cbcSMatt Macy 406*eda14cbcSMatt Macy *vtoc = vptr; 407*eda14cbcSMatt Macy 408*eda14cbcSMatt Macy vptr->efi_version = EFI_VERSION_CURRENT; 409*eda14cbcSMatt Macy vptr->efi_lbasize = lbsize; 410*eda14cbcSMatt Macy vptr->efi_nparts = nparts; 411*eda14cbcSMatt Macy /* 412*eda14cbcSMatt Macy * add one block here for the PMBR; on disks with a 512 byte 413*eda14cbcSMatt Macy * block size and 128 or fewer partitions, efi_first_u_lba 414*eda14cbcSMatt Macy * should work out to "34" 415*eda14cbcSMatt Macy */ 416*eda14cbcSMatt Macy vptr->efi_first_u_lba = nblocks + 1; 417*eda14cbcSMatt Macy vptr->efi_last_lba = capacity - 1; 418*eda14cbcSMatt Macy vptr->efi_altern_lba = capacity -1; 419*eda14cbcSMatt Macy vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks; 420*eda14cbcSMatt Macy 421*eda14cbcSMatt Macy (void) uuid_generate((uchar_t *)&uuid); 422*eda14cbcSMatt Macy UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid); 423*eda14cbcSMatt Macy return (0); 424*eda14cbcSMatt Macy } 425*eda14cbcSMatt Macy 426*eda14cbcSMatt Macy /* 427*eda14cbcSMatt Macy * Read EFI - return partition number upon success. 428*eda14cbcSMatt Macy */ 429*eda14cbcSMatt Macy int 430*eda14cbcSMatt Macy efi_alloc_and_read(int fd, struct dk_gpt **vtoc) 431*eda14cbcSMatt Macy { 432*eda14cbcSMatt Macy int rval; 433*eda14cbcSMatt Macy uint32_t nparts; 434*eda14cbcSMatt Macy int length; 435*eda14cbcSMatt Macy struct dk_gpt *vptr; 436*eda14cbcSMatt Macy 437*eda14cbcSMatt Macy /* figure out the number of entries that would fit into 16K */ 438*eda14cbcSMatt Macy nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t); 439*eda14cbcSMatt Macy length = (int) sizeof (struct dk_gpt) + 440*eda14cbcSMatt Macy (int) sizeof (struct dk_part) * (nparts - 1); 441*eda14cbcSMatt Macy vptr = calloc(1, length); 442*eda14cbcSMatt Macy 443*eda14cbcSMatt Macy if (vptr == NULL) 444*eda14cbcSMatt Macy return (VT_ERROR); 445*eda14cbcSMatt Macy 446*eda14cbcSMatt Macy vptr->efi_nparts = nparts; 447*eda14cbcSMatt Macy rval = efi_read(fd, vptr); 448*eda14cbcSMatt Macy 449*eda14cbcSMatt Macy if ((rval == VT_EINVAL) && vptr->efi_nparts > nparts) { 450*eda14cbcSMatt Macy void *tmp; 451*eda14cbcSMatt Macy length = (int) sizeof (struct dk_gpt) + 452*eda14cbcSMatt Macy (int) sizeof (struct dk_part) * (vptr->efi_nparts - 1); 453*eda14cbcSMatt Macy nparts = vptr->efi_nparts; 454*eda14cbcSMatt Macy if ((tmp = realloc(vptr, length)) == NULL) { 455*eda14cbcSMatt Macy free(vptr); 456*eda14cbcSMatt Macy *vtoc = NULL; 457*eda14cbcSMatt Macy return (VT_ERROR); 458*eda14cbcSMatt Macy } else { 459*eda14cbcSMatt Macy vptr = tmp; 460*eda14cbcSMatt Macy rval = efi_read(fd, vptr); 461*eda14cbcSMatt Macy } 462*eda14cbcSMatt Macy } 463*eda14cbcSMatt Macy 464*eda14cbcSMatt Macy if (rval < 0) { 465*eda14cbcSMatt Macy if (efi_debug) { 466*eda14cbcSMatt Macy (void) fprintf(stderr, 467*eda14cbcSMatt Macy "read of EFI table failed, rval=%d\n", rval); 468*eda14cbcSMatt Macy } 469*eda14cbcSMatt Macy free(vptr); 470*eda14cbcSMatt Macy *vtoc = NULL; 471*eda14cbcSMatt Macy } else { 472*eda14cbcSMatt Macy *vtoc = vptr; 473*eda14cbcSMatt Macy } 474*eda14cbcSMatt Macy 475*eda14cbcSMatt Macy return (rval); 476*eda14cbcSMatt Macy } 477*eda14cbcSMatt Macy 478*eda14cbcSMatt Macy static int 479*eda14cbcSMatt Macy efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc) 480*eda14cbcSMatt Macy { 481*eda14cbcSMatt Macy void *data = dk_ioc->dki_data; 482*eda14cbcSMatt Macy int error; 483*eda14cbcSMatt Macy diskaddr_t capacity; 484*eda14cbcSMatt Macy uint_t lbsize; 485*eda14cbcSMatt Macy 486*eda14cbcSMatt Macy /* 487*eda14cbcSMatt Macy * When the IO is not being performed in kernel as an ioctl we need 488*eda14cbcSMatt Macy * to know the sector size so we can seek to the proper byte offset. 489*eda14cbcSMatt Macy */ 490*eda14cbcSMatt Macy if (read_disk_info(fd, &capacity, &lbsize) == -1) { 491*eda14cbcSMatt Macy if (efi_debug) 492*eda14cbcSMatt Macy fprintf(stderr, "unable to read disk info: %d", errno); 493*eda14cbcSMatt Macy 494*eda14cbcSMatt Macy errno = EIO; 495*eda14cbcSMatt Macy return (-1); 496*eda14cbcSMatt Macy } 497*eda14cbcSMatt Macy 498*eda14cbcSMatt Macy switch (cmd) { 499*eda14cbcSMatt Macy case DKIOCGETEFI: 500*eda14cbcSMatt Macy if (lbsize == 0) { 501*eda14cbcSMatt Macy if (efi_debug) 502*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCGETEFI assuming " 503*eda14cbcSMatt Macy "LBA %d bytes\n", DEV_BSIZE); 504*eda14cbcSMatt Macy 505*eda14cbcSMatt Macy lbsize = DEV_BSIZE; 506*eda14cbcSMatt Macy } 507*eda14cbcSMatt Macy 508*eda14cbcSMatt Macy error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET); 509*eda14cbcSMatt Macy if (error == -1) { 510*eda14cbcSMatt Macy if (efi_debug) 511*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCGETEFI lseek " 512*eda14cbcSMatt Macy "error: %d\n", errno); 513*eda14cbcSMatt Macy return (error); 514*eda14cbcSMatt Macy } 515*eda14cbcSMatt Macy 516*eda14cbcSMatt Macy error = read(fd, data, dk_ioc->dki_length); 517*eda14cbcSMatt Macy if (error == -1) { 518*eda14cbcSMatt Macy if (efi_debug) 519*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCGETEFI read " 520*eda14cbcSMatt Macy "error: %d\n", errno); 521*eda14cbcSMatt Macy return (error); 522*eda14cbcSMatt Macy } 523*eda14cbcSMatt Macy 524*eda14cbcSMatt Macy if (error != dk_ioc->dki_length) { 525*eda14cbcSMatt Macy if (efi_debug) 526*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCGETEFI short " 527*eda14cbcSMatt Macy "read of %d bytes\n", error); 528*eda14cbcSMatt Macy errno = EIO; 529*eda14cbcSMatt Macy return (-1); 530*eda14cbcSMatt Macy } 531*eda14cbcSMatt Macy error = 0; 532*eda14cbcSMatt Macy break; 533*eda14cbcSMatt Macy 534*eda14cbcSMatt Macy case DKIOCSETEFI: 535*eda14cbcSMatt Macy if (lbsize == 0) { 536*eda14cbcSMatt Macy if (efi_debug) 537*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCSETEFI unknown " 538*eda14cbcSMatt Macy "LBA size\n"); 539*eda14cbcSMatt Macy errno = EIO; 540*eda14cbcSMatt Macy return (-1); 541*eda14cbcSMatt Macy } 542*eda14cbcSMatt Macy 543*eda14cbcSMatt Macy error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET); 544*eda14cbcSMatt Macy if (error == -1) { 545*eda14cbcSMatt Macy if (efi_debug) 546*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCSETEFI lseek " 547*eda14cbcSMatt Macy "error: %d\n", errno); 548*eda14cbcSMatt Macy return (error); 549*eda14cbcSMatt Macy } 550*eda14cbcSMatt Macy 551*eda14cbcSMatt Macy error = write(fd, data, dk_ioc->dki_length); 552*eda14cbcSMatt Macy if (error == -1) { 553*eda14cbcSMatt Macy if (efi_debug) 554*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCSETEFI write " 555*eda14cbcSMatt Macy "error: %d\n", errno); 556*eda14cbcSMatt Macy return (error); 557*eda14cbcSMatt Macy } 558*eda14cbcSMatt Macy 559*eda14cbcSMatt Macy if (error != dk_ioc->dki_length) { 560*eda14cbcSMatt Macy if (efi_debug) 561*eda14cbcSMatt Macy (void) fprintf(stderr, "DKIOCSETEFI short " 562*eda14cbcSMatt Macy "write of %d bytes\n", error); 563*eda14cbcSMatt Macy errno = EIO; 564*eda14cbcSMatt Macy return (-1); 565*eda14cbcSMatt Macy } 566*eda14cbcSMatt Macy 567*eda14cbcSMatt Macy /* Sync the new EFI table to disk */ 568*eda14cbcSMatt Macy error = fsync(fd); 569*eda14cbcSMatt Macy if (error == -1) 570*eda14cbcSMatt Macy return (error); 571*eda14cbcSMatt Macy 572*eda14cbcSMatt Macy /* Ensure any local disk cache is also flushed */ 573*eda14cbcSMatt Macy if (ioctl(fd, BLKFLSBUF, 0) == -1) 574*eda14cbcSMatt Macy return (error); 575*eda14cbcSMatt Macy 576*eda14cbcSMatt Macy error = 0; 577*eda14cbcSMatt Macy break; 578*eda14cbcSMatt Macy 579*eda14cbcSMatt Macy default: 580*eda14cbcSMatt Macy if (efi_debug) 581*eda14cbcSMatt Macy (void) fprintf(stderr, "unsupported ioctl()\n"); 582*eda14cbcSMatt Macy 583*eda14cbcSMatt Macy errno = EIO; 584*eda14cbcSMatt Macy return (-1); 585*eda14cbcSMatt Macy } 586*eda14cbcSMatt Macy 587*eda14cbcSMatt Macy return (error); 588*eda14cbcSMatt Macy } 589*eda14cbcSMatt Macy 590*eda14cbcSMatt Macy int 591*eda14cbcSMatt Macy efi_rescan(int fd) 592*eda14cbcSMatt Macy { 593*eda14cbcSMatt Macy int retry = 10; 594*eda14cbcSMatt Macy int error; 595*eda14cbcSMatt Macy 596*eda14cbcSMatt Macy /* Notify the kernel a devices partition table has been updated */ 597*eda14cbcSMatt Macy while ((error = ioctl(fd, BLKRRPART)) != 0) { 598*eda14cbcSMatt Macy if ((--retry == 0) || (errno != EBUSY)) { 599*eda14cbcSMatt Macy (void) fprintf(stderr, "the kernel failed to rescan " 600*eda14cbcSMatt Macy "the partition table: %d\n", errno); 601*eda14cbcSMatt Macy return (-1); 602*eda14cbcSMatt Macy } 603*eda14cbcSMatt Macy usleep(50000); 604*eda14cbcSMatt Macy } 605*eda14cbcSMatt Macy 606*eda14cbcSMatt Macy return (0); 607*eda14cbcSMatt Macy } 608*eda14cbcSMatt Macy 609*eda14cbcSMatt Macy static int 610*eda14cbcSMatt Macy check_label(int fd, dk_efi_t *dk_ioc) 611*eda14cbcSMatt Macy { 612*eda14cbcSMatt Macy efi_gpt_t *efi; 613*eda14cbcSMatt Macy uint_t crc; 614*eda14cbcSMatt Macy 615*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) { 616*eda14cbcSMatt Macy switch (errno) { 617*eda14cbcSMatt Macy case EIO: 618*eda14cbcSMatt Macy return (VT_EIO); 619*eda14cbcSMatt Macy default: 620*eda14cbcSMatt Macy return (VT_ERROR); 621*eda14cbcSMatt Macy } 622*eda14cbcSMatt Macy } 623*eda14cbcSMatt Macy efi = dk_ioc->dki_data; 624*eda14cbcSMatt Macy if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) { 625*eda14cbcSMatt Macy if (efi_debug) 626*eda14cbcSMatt Macy (void) fprintf(stderr, 627*eda14cbcSMatt Macy "Bad EFI signature: 0x%llx != 0x%llx\n", 628*eda14cbcSMatt Macy (long long)efi->efi_gpt_Signature, 629*eda14cbcSMatt Macy (long long)LE_64(EFI_SIGNATURE)); 630*eda14cbcSMatt Macy return (VT_EINVAL); 631*eda14cbcSMatt Macy } 632*eda14cbcSMatt Macy 633*eda14cbcSMatt Macy /* 634*eda14cbcSMatt Macy * check CRC of the header; the size of the header should 635*eda14cbcSMatt Macy * never be larger than one block 636*eda14cbcSMatt Macy */ 637*eda14cbcSMatt Macy crc = efi->efi_gpt_HeaderCRC32; 638*eda14cbcSMatt Macy efi->efi_gpt_HeaderCRC32 = 0; 639*eda14cbcSMatt Macy len_t headerSize = (len_t)LE_32(efi->efi_gpt_HeaderSize); 640*eda14cbcSMatt Macy 641*eda14cbcSMatt Macy if (headerSize < EFI_MIN_LABEL_SIZE || headerSize > EFI_LABEL_SIZE) { 642*eda14cbcSMatt Macy if (efi_debug) 643*eda14cbcSMatt Macy (void) fprintf(stderr, 644*eda14cbcSMatt Macy "Invalid EFI HeaderSize %llu. Assuming %d.\n", 645*eda14cbcSMatt Macy headerSize, EFI_MIN_LABEL_SIZE); 646*eda14cbcSMatt Macy } 647*eda14cbcSMatt Macy 648*eda14cbcSMatt Macy if ((headerSize > dk_ioc->dki_length) || 649*eda14cbcSMatt Macy crc != LE_32(efi_crc32((unsigned char *)efi, headerSize))) { 650*eda14cbcSMatt Macy if (efi_debug) 651*eda14cbcSMatt Macy (void) fprintf(stderr, 652*eda14cbcSMatt Macy "Bad EFI CRC: 0x%x != 0x%x\n", 653*eda14cbcSMatt Macy crc, LE_32(efi_crc32((unsigned char *)efi, 654*eda14cbcSMatt Macy headerSize))); 655*eda14cbcSMatt Macy return (VT_EINVAL); 656*eda14cbcSMatt Macy } 657*eda14cbcSMatt Macy 658*eda14cbcSMatt Macy return (0); 659*eda14cbcSMatt Macy } 660*eda14cbcSMatt Macy 661*eda14cbcSMatt Macy static int 662*eda14cbcSMatt Macy efi_read(int fd, struct dk_gpt *vtoc) 663*eda14cbcSMatt Macy { 664*eda14cbcSMatt Macy int i, j; 665*eda14cbcSMatt Macy int label_len; 666*eda14cbcSMatt Macy int rval = 0; 667*eda14cbcSMatt Macy int md_flag = 0; 668*eda14cbcSMatt Macy int vdc_flag = 0; 669*eda14cbcSMatt Macy diskaddr_t capacity = 0; 670*eda14cbcSMatt Macy uint_t lbsize = 0; 671*eda14cbcSMatt Macy struct dk_minfo disk_info; 672*eda14cbcSMatt Macy dk_efi_t dk_ioc; 673*eda14cbcSMatt Macy efi_gpt_t *efi; 674*eda14cbcSMatt Macy efi_gpe_t *efi_parts; 675*eda14cbcSMatt Macy struct dk_cinfo dki_info; 676*eda14cbcSMatt Macy uint32_t user_length; 677*eda14cbcSMatt Macy boolean_t legacy_label = B_FALSE; 678*eda14cbcSMatt Macy 679*eda14cbcSMatt Macy /* 680*eda14cbcSMatt Macy * get the partition number for this file descriptor. 681*eda14cbcSMatt Macy */ 682*eda14cbcSMatt Macy if ((rval = efi_get_info(fd, &dki_info)) != 0) 683*eda14cbcSMatt Macy return (rval); 684*eda14cbcSMatt Macy 685*eda14cbcSMatt Macy if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) && 686*eda14cbcSMatt Macy (strncmp(dki_info.dki_dname, "md", 3) == 0)) { 687*eda14cbcSMatt Macy md_flag++; 688*eda14cbcSMatt Macy } else if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) && 689*eda14cbcSMatt Macy (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) { 690*eda14cbcSMatt Macy /* 691*eda14cbcSMatt Macy * The controller and drive name "vdc" (virtual disk client) 692*eda14cbcSMatt Macy * indicates a LDoms virtual disk. 693*eda14cbcSMatt Macy */ 694*eda14cbcSMatt Macy vdc_flag++; 695*eda14cbcSMatt Macy } 696*eda14cbcSMatt Macy 697*eda14cbcSMatt Macy /* get the LBA size */ 698*eda14cbcSMatt Macy if (read_disk_info(fd, &capacity, &lbsize) == -1) { 699*eda14cbcSMatt Macy if (efi_debug) { 700*eda14cbcSMatt Macy (void) fprintf(stderr, 701*eda14cbcSMatt Macy "unable to read disk info: %d", 702*eda14cbcSMatt Macy errno); 703*eda14cbcSMatt Macy } 704*eda14cbcSMatt Macy return (VT_EINVAL); 705*eda14cbcSMatt Macy } 706*eda14cbcSMatt Macy 707*eda14cbcSMatt Macy disk_info.dki_lbsize = lbsize; 708*eda14cbcSMatt Macy disk_info.dki_capacity = capacity; 709*eda14cbcSMatt Macy 710*eda14cbcSMatt Macy if (disk_info.dki_lbsize == 0) { 711*eda14cbcSMatt Macy if (efi_debug) { 712*eda14cbcSMatt Macy (void) fprintf(stderr, 713*eda14cbcSMatt Macy "efi_read: assuming LBA 512 bytes\n"); 714*eda14cbcSMatt Macy } 715*eda14cbcSMatt Macy disk_info.dki_lbsize = DEV_BSIZE; 716*eda14cbcSMatt Macy } 717*eda14cbcSMatt Macy /* 718*eda14cbcSMatt Macy * Read the EFI GPT to figure out how many partitions we need 719*eda14cbcSMatt Macy * to deal with. 720*eda14cbcSMatt Macy */ 721*eda14cbcSMatt Macy dk_ioc.dki_lba = 1; 722*eda14cbcSMatt Macy if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) { 723*eda14cbcSMatt Macy label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize; 724*eda14cbcSMatt Macy } else { 725*eda14cbcSMatt Macy label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) + 726*eda14cbcSMatt Macy disk_info.dki_lbsize; 727*eda14cbcSMatt Macy if (label_len % disk_info.dki_lbsize) { 728*eda14cbcSMatt Macy /* pad to physical sector size */ 729*eda14cbcSMatt Macy label_len += disk_info.dki_lbsize; 730*eda14cbcSMatt Macy label_len &= ~(disk_info.dki_lbsize - 1); 731*eda14cbcSMatt Macy } 732*eda14cbcSMatt Macy } 733*eda14cbcSMatt Macy 734*eda14cbcSMatt Macy if (posix_memalign((void **)&dk_ioc.dki_data, 735*eda14cbcSMatt Macy disk_info.dki_lbsize, label_len)) 736*eda14cbcSMatt Macy return (VT_ERROR); 737*eda14cbcSMatt Macy 738*eda14cbcSMatt Macy memset(dk_ioc.dki_data, 0, label_len); 739*eda14cbcSMatt Macy dk_ioc.dki_length = disk_info.dki_lbsize; 740*eda14cbcSMatt Macy user_length = vtoc->efi_nparts; 741*eda14cbcSMatt Macy efi = dk_ioc.dki_data; 742*eda14cbcSMatt Macy if (md_flag) { 743*eda14cbcSMatt Macy dk_ioc.dki_length = label_len; 744*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) { 745*eda14cbcSMatt Macy switch (errno) { 746*eda14cbcSMatt Macy case EIO: 747*eda14cbcSMatt Macy return (VT_EIO); 748*eda14cbcSMatt Macy default: 749*eda14cbcSMatt Macy return (VT_ERROR); 750*eda14cbcSMatt Macy } 751*eda14cbcSMatt Macy } 752*eda14cbcSMatt Macy } else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) { 753*eda14cbcSMatt Macy /* 754*eda14cbcSMatt Macy * No valid label here; try the alternate. Note that here 755*eda14cbcSMatt Macy * we just read GPT header and save it into dk_ioc.data, 756*eda14cbcSMatt Macy * Later, we will read GUID partition entry array if we 757*eda14cbcSMatt Macy * can get valid GPT header. 758*eda14cbcSMatt Macy */ 759*eda14cbcSMatt Macy 760*eda14cbcSMatt Macy /* 761*eda14cbcSMatt Macy * This is a workaround for legacy systems. In the past, the 762*eda14cbcSMatt Macy * last sector of SCSI disk was invisible on x86 platform. At 763*eda14cbcSMatt Macy * that time, backup label was saved on the next to the last 764*eda14cbcSMatt Macy * sector. It is possible for users to move a disk from previous 765*eda14cbcSMatt Macy * solaris system to present system. Here, we attempt to search 766*eda14cbcSMatt Macy * legacy backup EFI label first. 767*eda14cbcSMatt Macy */ 768*eda14cbcSMatt Macy dk_ioc.dki_lba = disk_info.dki_capacity - 2; 769*eda14cbcSMatt Macy dk_ioc.dki_length = disk_info.dki_lbsize; 770*eda14cbcSMatt Macy rval = check_label(fd, &dk_ioc); 771*eda14cbcSMatt Macy if (rval == VT_EINVAL) { 772*eda14cbcSMatt Macy /* 773*eda14cbcSMatt Macy * we didn't find legacy backup EFI label, try to 774*eda14cbcSMatt Macy * search backup EFI label in the last block. 775*eda14cbcSMatt Macy */ 776*eda14cbcSMatt Macy dk_ioc.dki_lba = disk_info.dki_capacity - 1; 777*eda14cbcSMatt Macy dk_ioc.dki_length = disk_info.dki_lbsize; 778*eda14cbcSMatt Macy rval = check_label(fd, &dk_ioc); 779*eda14cbcSMatt Macy if (rval == 0) { 780*eda14cbcSMatt Macy legacy_label = B_TRUE; 781*eda14cbcSMatt Macy if (efi_debug) 782*eda14cbcSMatt Macy (void) fprintf(stderr, 783*eda14cbcSMatt Macy "efi_read: primary label corrupt; " 784*eda14cbcSMatt Macy "using EFI backup label located on" 785*eda14cbcSMatt Macy " the last block\n"); 786*eda14cbcSMatt Macy } 787*eda14cbcSMatt Macy } else { 788*eda14cbcSMatt Macy if ((efi_debug) && (rval == 0)) 789*eda14cbcSMatt Macy (void) fprintf(stderr, "efi_read: primary label" 790*eda14cbcSMatt Macy " corrupt; using legacy EFI backup label " 791*eda14cbcSMatt Macy " located on the next to last block\n"); 792*eda14cbcSMatt Macy } 793*eda14cbcSMatt Macy 794*eda14cbcSMatt Macy if (rval == 0) { 795*eda14cbcSMatt Macy dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA); 796*eda14cbcSMatt Macy vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT; 797*eda14cbcSMatt Macy vtoc->efi_nparts = 798*eda14cbcSMatt Macy LE_32(efi->efi_gpt_NumberOfPartitionEntries); 799*eda14cbcSMatt Macy /* 800*eda14cbcSMatt Macy * Partition tables are between backup GPT header 801*eda14cbcSMatt Macy * table and ParitionEntryLBA (the starting LBA of 802*eda14cbcSMatt Macy * the GUID partition entries array). Now that we 803*eda14cbcSMatt Macy * already got valid GPT header and saved it in 804*eda14cbcSMatt Macy * dk_ioc.dki_data, we try to get GUID partition 805*eda14cbcSMatt Macy * entry array here. 806*eda14cbcSMatt Macy */ 807*eda14cbcSMatt Macy /* LINTED */ 808*eda14cbcSMatt Macy dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data 809*eda14cbcSMatt Macy + disk_info.dki_lbsize); 810*eda14cbcSMatt Macy if (legacy_label) 811*eda14cbcSMatt Macy dk_ioc.dki_length = disk_info.dki_capacity - 1 - 812*eda14cbcSMatt Macy dk_ioc.dki_lba; 813*eda14cbcSMatt Macy else 814*eda14cbcSMatt Macy dk_ioc.dki_length = disk_info.dki_capacity - 2 - 815*eda14cbcSMatt Macy dk_ioc.dki_lba; 816*eda14cbcSMatt Macy dk_ioc.dki_length *= disk_info.dki_lbsize; 817*eda14cbcSMatt Macy if (dk_ioc.dki_length > 818*eda14cbcSMatt Macy ((len_t)label_len - sizeof (*dk_ioc.dki_data))) { 819*eda14cbcSMatt Macy rval = VT_EINVAL; 820*eda14cbcSMatt Macy } else { 821*eda14cbcSMatt Macy /* 822*eda14cbcSMatt Macy * read GUID partition entry array 823*eda14cbcSMatt Macy */ 824*eda14cbcSMatt Macy rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc); 825*eda14cbcSMatt Macy } 826*eda14cbcSMatt Macy } 827*eda14cbcSMatt Macy 828*eda14cbcSMatt Macy } else if (rval == 0) { 829*eda14cbcSMatt Macy 830*eda14cbcSMatt Macy dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA); 831*eda14cbcSMatt Macy /* LINTED */ 832*eda14cbcSMatt Macy dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data 833*eda14cbcSMatt Macy + disk_info.dki_lbsize); 834*eda14cbcSMatt Macy dk_ioc.dki_length = label_len - disk_info.dki_lbsize; 835*eda14cbcSMatt Macy rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc); 836*eda14cbcSMatt Macy 837*eda14cbcSMatt Macy } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) { 838*eda14cbcSMatt Macy /* 839*eda14cbcSMatt Macy * When the device is a LDoms virtual disk, the DKIOCGETEFI 840*eda14cbcSMatt Macy * ioctl can fail with EINVAL if the virtual disk backend 841*eda14cbcSMatt Macy * is a ZFS volume serviced by a domain running an old version 842*eda14cbcSMatt Macy * of Solaris. This is because the DKIOCGETEFI ioctl was 843*eda14cbcSMatt Macy * initially incorrectly implemented for a ZFS volume and it 844*eda14cbcSMatt Macy * expected the GPT and GPE to be retrieved with a single ioctl. 845*eda14cbcSMatt Macy * So we try to read the GPT and the GPE using that old style 846*eda14cbcSMatt Macy * ioctl. 847*eda14cbcSMatt Macy */ 848*eda14cbcSMatt Macy dk_ioc.dki_lba = 1; 849*eda14cbcSMatt Macy dk_ioc.dki_length = label_len; 850*eda14cbcSMatt Macy rval = check_label(fd, &dk_ioc); 851*eda14cbcSMatt Macy } 852*eda14cbcSMatt Macy 853*eda14cbcSMatt Macy if (rval < 0) { 854*eda14cbcSMatt Macy free(efi); 855*eda14cbcSMatt Macy return (rval); 856*eda14cbcSMatt Macy } 857*eda14cbcSMatt Macy 858*eda14cbcSMatt Macy /* LINTED -- always longlong aligned */ 859*eda14cbcSMatt Macy efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize); 860*eda14cbcSMatt Macy 861*eda14cbcSMatt Macy /* 862*eda14cbcSMatt Macy * Assemble this into a "dk_gpt" struct for easier 863*eda14cbcSMatt Macy * digestibility by applications. 864*eda14cbcSMatt Macy */ 865*eda14cbcSMatt Macy vtoc->efi_version = LE_32(efi->efi_gpt_Revision); 866*eda14cbcSMatt Macy vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries); 867*eda14cbcSMatt Macy vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry); 868*eda14cbcSMatt Macy vtoc->efi_lbasize = disk_info.dki_lbsize; 869*eda14cbcSMatt Macy vtoc->efi_last_lba = disk_info.dki_capacity - 1; 870*eda14cbcSMatt Macy vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA); 871*eda14cbcSMatt Macy vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA); 872*eda14cbcSMatt Macy vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA); 873*eda14cbcSMatt Macy UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID); 874*eda14cbcSMatt Macy 875*eda14cbcSMatt Macy /* 876*eda14cbcSMatt Macy * If the array the user passed in is too small, set the length 877*eda14cbcSMatt Macy * to what it needs to be and return 878*eda14cbcSMatt Macy */ 879*eda14cbcSMatt Macy if (user_length < vtoc->efi_nparts) { 880*eda14cbcSMatt Macy return (VT_EINVAL); 881*eda14cbcSMatt Macy } 882*eda14cbcSMatt Macy 883*eda14cbcSMatt Macy for (i = 0; i < vtoc->efi_nparts; i++) { 884*eda14cbcSMatt Macy 885*eda14cbcSMatt Macy UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid, 886*eda14cbcSMatt Macy efi_parts[i].efi_gpe_PartitionTypeGUID); 887*eda14cbcSMatt Macy 888*eda14cbcSMatt Macy for (j = 0; 889*eda14cbcSMatt Macy j < sizeof (conversion_array) 890*eda14cbcSMatt Macy / sizeof (struct uuid_to_ptag); j++) { 891*eda14cbcSMatt Macy 892*eda14cbcSMatt Macy if (bcmp(&vtoc->efi_parts[i].p_guid, 893*eda14cbcSMatt Macy &conversion_array[j].uuid, 894*eda14cbcSMatt Macy sizeof (struct uuid)) == 0) { 895*eda14cbcSMatt Macy vtoc->efi_parts[i].p_tag = j; 896*eda14cbcSMatt Macy break; 897*eda14cbcSMatt Macy } 898*eda14cbcSMatt Macy } 899*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) 900*eda14cbcSMatt Macy continue; 901*eda14cbcSMatt Macy vtoc->efi_parts[i].p_flag = 902*eda14cbcSMatt Macy LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs); 903*eda14cbcSMatt Macy vtoc->efi_parts[i].p_start = 904*eda14cbcSMatt Macy LE_64(efi_parts[i].efi_gpe_StartingLBA); 905*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size = 906*eda14cbcSMatt Macy LE_64(efi_parts[i].efi_gpe_EndingLBA) - 907*eda14cbcSMatt Macy vtoc->efi_parts[i].p_start + 1; 908*eda14cbcSMatt Macy for (j = 0; j < EFI_PART_NAME_LEN; j++) { 909*eda14cbcSMatt Macy vtoc->efi_parts[i].p_name[j] = 910*eda14cbcSMatt Macy (uchar_t)LE_16( 911*eda14cbcSMatt Macy efi_parts[i].efi_gpe_PartitionName[j]); 912*eda14cbcSMatt Macy } 913*eda14cbcSMatt Macy 914*eda14cbcSMatt Macy UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid, 915*eda14cbcSMatt Macy efi_parts[i].efi_gpe_UniquePartitionGUID); 916*eda14cbcSMatt Macy } 917*eda14cbcSMatt Macy free(efi); 918*eda14cbcSMatt Macy 919*eda14cbcSMatt Macy return (dki_info.dki_partition); 920*eda14cbcSMatt Macy } 921*eda14cbcSMatt Macy 922*eda14cbcSMatt Macy /* writes a "protective" MBR */ 923*eda14cbcSMatt Macy static int 924*eda14cbcSMatt Macy write_pmbr(int fd, struct dk_gpt *vtoc) 925*eda14cbcSMatt Macy { 926*eda14cbcSMatt Macy dk_efi_t dk_ioc; 927*eda14cbcSMatt Macy struct mboot mb; 928*eda14cbcSMatt Macy uchar_t *cp; 929*eda14cbcSMatt Macy diskaddr_t size_in_lba; 930*eda14cbcSMatt Macy uchar_t *buf; 931*eda14cbcSMatt Macy int len; 932*eda14cbcSMatt Macy 933*eda14cbcSMatt Macy len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize; 934*eda14cbcSMatt Macy if (posix_memalign((void **)&buf, len, len)) 935*eda14cbcSMatt Macy return (VT_ERROR); 936*eda14cbcSMatt Macy 937*eda14cbcSMatt Macy /* 938*eda14cbcSMatt Macy * Preserve any boot code and disk signature if the first block is 939*eda14cbcSMatt Macy * already an MBR. 940*eda14cbcSMatt Macy */ 941*eda14cbcSMatt Macy memset(buf, 0, len); 942*eda14cbcSMatt Macy dk_ioc.dki_lba = 0; 943*eda14cbcSMatt Macy dk_ioc.dki_length = len; 944*eda14cbcSMatt Macy /* LINTED -- always longlong aligned */ 945*eda14cbcSMatt Macy dk_ioc.dki_data = (efi_gpt_t *)buf; 946*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) { 947*eda14cbcSMatt Macy (void) memcpy(&mb, buf, sizeof (mb)); 948*eda14cbcSMatt Macy bzero(&mb, sizeof (mb)); 949*eda14cbcSMatt Macy mb.signature = LE_16(MBB_MAGIC); 950*eda14cbcSMatt Macy } else { 951*eda14cbcSMatt Macy (void) memcpy(&mb, buf, sizeof (mb)); 952*eda14cbcSMatt Macy if (mb.signature != LE_16(MBB_MAGIC)) { 953*eda14cbcSMatt Macy bzero(&mb, sizeof (mb)); 954*eda14cbcSMatt Macy mb.signature = LE_16(MBB_MAGIC); 955*eda14cbcSMatt Macy } 956*eda14cbcSMatt Macy } 957*eda14cbcSMatt Macy 958*eda14cbcSMatt Macy bzero(&mb.parts, sizeof (mb.parts)); 959*eda14cbcSMatt Macy cp = (uchar_t *)&mb.parts[0]; 960*eda14cbcSMatt Macy /* bootable or not */ 961*eda14cbcSMatt Macy *cp++ = 0; 962*eda14cbcSMatt Macy /* beginning CHS; 0xffffff if not representable */ 963*eda14cbcSMatt Macy *cp++ = 0xff; 964*eda14cbcSMatt Macy *cp++ = 0xff; 965*eda14cbcSMatt Macy *cp++ = 0xff; 966*eda14cbcSMatt Macy /* OS type */ 967*eda14cbcSMatt Macy *cp++ = EFI_PMBR; 968*eda14cbcSMatt Macy /* ending CHS; 0xffffff if not representable */ 969*eda14cbcSMatt Macy *cp++ = 0xff; 970*eda14cbcSMatt Macy *cp++ = 0xff; 971*eda14cbcSMatt Macy *cp++ = 0xff; 972*eda14cbcSMatt Macy /* starting LBA: 1 (little endian format) by EFI definition */ 973*eda14cbcSMatt Macy *cp++ = 0x01; 974*eda14cbcSMatt Macy *cp++ = 0x00; 975*eda14cbcSMatt Macy *cp++ = 0x00; 976*eda14cbcSMatt Macy *cp++ = 0x00; 977*eda14cbcSMatt Macy /* ending LBA: last block on the disk (little endian format) */ 978*eda14cbcSMatt Macy size_in_lba = vtoc->efi_last_lba; 979*eda14cbcSMatt Macy if (size_in_lba < 0xffffffff) { 980*eda14cbcSMatt Macy *cp++ = (size_in_lba & 0x000000ff); 981*eda14cbcSMatt Macy *cp++ = (size_in_lba & 0x0000ff00) >> 8; 982*eda14cbcSMatt Macy *cp++ = (size_in_lba & 0x00ff0000) >> 16; 983*eda14cbcSMatt Macy *cp++ = (size_in_lba & 0xff000000) >> 24; 984*eda14cbcSMatt Macy } else { 985*eda14cbcSMatt Macy *cp++ = 0xff; 986*eda14cbcSMatt Macy *cp++ = 0xff; 987*eda14cbcSMatt Macy *cp++ = 0xff; 988*eda14cbcSMatt Macy *cp++ = 0xff; 989*eda14cbcSMatt Macy } 990*eda14cbcSMatt Macy 991*eda14cbcSMatt Macy (void) memcpy(buf, &mb, sizeof (mb)); 992*eda14cbcSMatt Macy /* LINTED -- always longlong aligned */ 993*eda14cbcSMatt Macy dk_ioc.dki_data = (efi_gpt_t *)buf; 994*eda14cbcSMatt Macy dk_ioc.dki_lba = 0; 995*eda14cbcSMatt Macy dk_ioc.dki_length = len; 996*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { 997*eda14cbcSMatt Macy free(buf); 998*eda14cbcSMatt Macy switch (errno) { 999*eda14cbcSMatt Macy case EIO: 1000*eda14cbcSMatt Macy return (VT_EIO); 1001*eda14cbcSMatt Macy case EINVAL: 1002*eda14cbcSMatt Macy return (VT_EINVAL); 1003*eda14cbcSMatt Macy default: 1004*eda14cbcSMatt Macy return (VT_ERROR); 1005*eda14cbcSMatt Macy } 1006*eda14cbcSMatt Macy } 1007*eda14cbcSMatt Macy free(buf); 1008*eda14cbcSMatt Macy return (0); 1009*eda14cbcSMatt Macy } 1010*eda14cbcSMatt Macy 1011*eda14cbcSMatt Macy /* make sure the user specified something reasonable */ 1012*eda14cbcSMatt Macy static int 1013*eda14cbcSMatt Macy check_input(struct dk_gpt *vtoc) 1014*eda14cbcSMatt Macy { 1015*eda14cbcSMatt Macy int resv_part = -1; 1016*eda14cbcSMatt Macy int i, j; 1017*eda14cbcSMatt Macy diskaddr_t istart, jstart, isize, jsize, endsect; 1018*eda14cbcSMatt Macy 1019*eda14cbcSMatt Macy /* 1020*eda14cbcSMatt Macy * Sanity-check the input (make sure no partitions overlap) 1021*eda14cbcSMatt Macy */ 1022*eda14cbcSMatt Macy for (i = 0; i < vtoc->efi_nparts; i++) { 1023*eda14cbcSMatt Macy /* It can't be unassigned and have an actual size */ 1024*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) && 1025*eda14cbcSMatt Macy (vtoc->efi_parts[i].p_size != 0)) { 1026*eda14cbcSMatt Macy if (efi_debug) { 1027*eda14cbcSMatt Macy (void) fprintf(stderr, "partition %d is " 1028*eda14cbcSMatt Macy "\"unassigned\" but has a size of %llu", 1029*eda14cbcSMatt Macy i, vtoc->efi_parts[i].p_size); 1030*eda14cbcSMatt Macy } 1031*eda14cbcSMatt Macy return (VT_EINVAL); 1032*eda14cbcSMatt Macy } 1033*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) { 1034*eda14cbcSMatt Macy if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid)) 1035*eda14cbcSMatt Macy continue; 1036*eda14cbcSMatt Macy /* we have encountered an unknown uuid */ 1037*eda14cbcSMatt Macy vtoc->efi_parts[i].p_tag = 0xff; 1038*eda14cbcSMatt Macy } 1039*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == V_RESERVED) { 1040*eda14cbcSMatt Macy if (resv_part != -1) { 1041*eda14cbcSMatt Macy if (efi_debug) { 1042*eda14cbcSMatt Macy (void) fprintf(stderr, "found " 1043*eda14cbcSMatt Macy "duplicate reserved partition " 1044*eda14cbcSMatt Macy "at %d\n", i); 1045*eda14cbcSMatt Macy } 1046*eda14cbcSMatt Macy return (VT_EINVAL); 1047*eda14cbcSMatt Macy } 1048*eda14cbcSMatt Macy resv_part = i; 1049*eda14cbcSMatt Macy } 1050*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) || 1051*eda14cbcSMatt Macy (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) { 1052*eda14cbcSMatt Macy if (efi_debug) { 1053*eda14cbcSMatt Macy (void) fprintf(stderr, 1054*eda14cbcSMatt Macy "Partition %d starts at %llu. ", 1055*eda14cbcSMatt Macy i, 1056*eda14cbcSMatt Macy vtoc->efi_parts[i].p_start); 1057*eda14cbcSMatt Macy (void) fprintf(stderr, 1058*eda14cbcSMatt Macy "It must be between %llu and %llu.\n", 1059*eda14cbcSMatt Macy vtoc->efi_first_u_lba, 1060*eda14cbcSMatt Macy vtoc->efi_last_u_lba); 1061*eda14cbcSMatt Macy } 1062*eda14cbcSMatt Macy return (VT_EINVAL); 1063*eda14cbcSMatt Macy } 1064*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_start + 1065*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size < 1066*eda14cbcSMatt Macy vtoc->efi_first_u_lba) || 1067*eda14cbcSMatt Macy (vtoc->efi_parts[i].p_start + 1068*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size > 1069*eda14cbcSMatt Macy vtoc->efi_last_u_lba + 1)) { 1070*eda14cbcSMatt Macy if (efi_debug) { 1071*eda14cbcSMatt Macy (void) fprintf(stderr, 1072*eda14cbcSMatt Macy "Partition %d ends at %llu. ", 1073*eda14cbcSMatt Macy i, 1074*eda14cbcSMatt Macy vtoc->efi_parts[i].p_start + 1075*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size); 1076*eda14cbcSMatt Macy (void) fprintf(stderr, 1077*eda14cbcSMatt Macy "It must be between %llu and %llu.\n", 1078*eda14cbcSMatt Macy vtoc->efi_first_u_lba, 1079*eda14cbcSMatt Macy vtoc->efi_last_u_lba); 1080*eda14cbcSMatt Macy } 1081*eda14cbcSMatt Macy return (VT_EINVAL); 1082*eda14cbcSMatt Macy } 1083*eda14cbcSMatt Macy 1084*eda14cbcSMatt Macy for (j = 0; j < vtoc->efi_nparts; j++) { 1085*eda14cbcSMatt Macy isize = vtoc->efi_parts[i].p_size; 1086*eda14cbcSMatt Macy jsize = vtoc->efi_parts[j].p_size; 1087*eda14cbcSMatt Macy istart = vtoc->efi_parts[i].p_start; 1088*eda14cbcSMatt Macy jstart = vtoc->efi_parts[j].p_start; 1089*eda14cbcSMatt Macy if ((i != j) && (isize != 0) && (jsize != 0)) { 1090*eda14cbcSMatt Macy endsect = jstart + jsize -1; 1091*eda14cbcSMatt Macy if ((jstart <= istart) && 1092*eda14cbcSMatt Macy (istart <= endsect)) { 1093*eda14cbcSMatt Macy if (efi_debug) { 1094*eda14cbcSMatt Macy (void) fprintf(stderr, 1095*eda14cbcSMatt Macy "Partition %d overlaps " 1096*eda14cbcSMatt Macy "partition %d.", i, j); 1097*eda14cbcSMatt Macy } 1098*eda14cbcSMatt Macy return (VT_EINVAL); 1099*eda14cbcSMatt Macy } 1100*eda14cbcSMatt Macy } 1101*eda14cbcSMatt Macy } 1102*eda14cbcSMatt Macy } 1103*eda14cbcSMatt Macy /* just a warning for now */ 1104*eda14cbcSMatt Macy if ((resv_part == -1) && efi_debug) { 1105*eda14cbcSMatt Macy (void) fprintf(stderr, 1106*eda14cbcSMatt Macy "no reserved partition found\n"); 1107*eda14cbcSMatt Macy } 1108*eda14cbcSMatt Macy return (0); 1109*eda14cbcSMatt Macy } 1110*eda14cbcSMatt Macy 1111*eda14cbcSMatt Macy /* 1112*eda14cbcSMatt Macy * add all the unallocated space to the current label 1113*eda14cbcSMatt Macy */ 1114*eda14cbcSMatt Macy int 1115*eda14cbcSMatt Macy efi_use_whole_disk(int fd) 1116*eda14cbcSMatt Macy { 1117*eda14cbcSMatt Macy struct dk_gpt *efi_label = NULL; 1118*eda14cbcSMatt Macy int rval; 1119*eda14cbcSMatt Macy int i; 1120*eda14cbcSMatt Macy uint_t resv_index = 0, data_index = 0; 1121*eda14cbcSMatt Macy diskaddr_t resv_start = 0, data_start = 0; 1122*eda14cbcSMatt Macy diskaddr_t data_size, limit, difference; 1123*eda14cbcSMatt Macy boolean_t sync_needed = B_FALSE; 1124*eda14cbcSMatt Macy uint_t nblocks; 1125*eda14cbcSMatt Macy 1126*eda14cbcSMatt Macy rval = efi_alloc_and_read(fd, &efi_label); 1127*eda14cbcSMatt Macy if (rval < 0) { 1128*eda14cbcSMatt Macy if (efi_label != NULL) 1129*eda14cbcSMatt Macy efi_free(efi_label); 1130*eda14cbcSMatt Macy return (rval); 1131*eda14cbcSMatt Macy } 1132*eda14cbcSMatt Macy 1133*eda14cbcSMatt Macy /* 1134*eda14cbcSMatt Macy * Find the last physically non-zero partition. 1135*eda14cbcSMatt Macy * This should be the reserved partition. 1136*eda14cbcSMatt Macy */ 1137*eda14cbcSMatt Macy for (i = 0; i < efi_label->efi_nparts; i ++) { 1138*eda14cbcSMatt Macy if (resv_start < efi_label->efi_parts[i].p_start) { 1139*eda14cbcSMatt Macy resv_start = efi_label->efi_parts[i].p_start; 1140*eda14cbcSMatt Macy resv_index = i; 1141*eda14cbcSMatt Macy } 1142*eda14cbcSMatt Macy } 1143*eda14cbcSMatt Macy 1144*eda14cbcSMatt Macy /* 1145*eda14cbcSMatt Macy * Find the last physically non-zero partition before that. 1146*eda14cbcSMatt Macy * This is the data partition. 1147*eda14cbcSMatt Macy */ 1148*eda14cbcSMatt Macy for (i = 0; i < resv_index; i ++) { 1149*eda14cbcSMatt Macy if (data_start < efi_label->efi_parts[i].p_start) { 1150*eda14cbcSMatt Macy data_start = efi_label->efi_parts[i].p_start; 1151*eda14cbcSMatt Macy data_index = i; 1152*eda14cbcSMatt Macy } 1153*eda14cbcSMatt Macy } 1154*eda14cbcSMatt Macy data_size = efi_label->efi_parts[data_index].p_size; 1155*eda14cbcSMatt Macy 1156*eda14cbcSMatt Macy /* 1157*eda14cbcSMatt Macy * See the "efi_alloc_and_init" function for more information 1158*eda14cbcSMatt Macy * about where this "nblocks" value comes from. 1159*eda14cbcSMatt Macy */ 1160*eda14cbcSMatt Macy nblocks = efi_label->efi_first_u_lba - 1; 1161*eda14cbcSMatt Macy 1162*eda14cbcSMatt Macy /* 1163*eda14cbcSMatt Macy * Determine if the EFI label is out of sync. We check that: 1164*eda14cbcSMatt Macy * 1165*eda14cbcSMatt Macy * 1. the data partition ends at the limit we set, and 1166*eda14cbcSMatt Macy * 2. the reserved partition starts at the limit we set. 1167*eda14cbcSMatt Macy * 1168*eda14cbcSMatt Macy * If either of these conditions is not met, then we need to 1169*eda14cbcSMatt Macy * resync the EFI label. 1170*eda14cbcSMatt Macy * 1171*eda14cbcSMatt Macy * The limit is the last usable LBA, determined by the last LBA 1172*eda14cbcSMatt Macy * and the first usable LBA fields on the EFI label of the disk 1173*eda14cbcSMatt Macy * (see the lines directly above). Additionally, we factor in 1174*eda14cbcSMatt Macy * EFI_MIN_RESV_SIZE (per its use in "zpool_label_disk") and 1175*eda14cbcSMatt Macy * P2ALIGN it to ensure the partition boundaries are aligned 1176*eda14cbcSMatt Macy * (for performance reasons). The alignment should match the 1177*eda14cbcSMatt Macy * alignment used by the "zpool_label_disk" function. 1178*eda14cbcSMatt Macy */ 1179*eda14cbcSMatt Macy limit = P2ALIGN(efi_label->efi_last_lba - nblocks - EFI_MIN_RESV_SIZE, 1180*eda14cbcSMatt Macy PARTITION_END_ALIGNMENT); 1181*eda14cbcSMatt Macy if (data_start + data_size != limit || resv_start != limit) 1182*eda14cbcSMatt Macy sync_needed = B_TRUE; 1183*eda14cbcSMatt Macy 1184*eda14cbcSMatt Macy if (efi_debug && sync_needed) 1185*eda14cbcSMatt Macy (void) fprintf(stderr, "efi_use_whole_disk: sync needed\n"); 1186*eda14cbcSMatt Macy 1187*eda14cbcSMatt Macy /* 1188*eda14cbcSMatt Macy * If alter_lba is 1, we are using the backup label. 1189*eda14cbcSMatt Macy * Since we can locate the backup label by disk capacity, 1190*eda14cbcSMatt Macy * there must be no unallocated space. 1191*eda14cbcSMatt Macy */ 1192*eda14cbcSMatt Macy if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba 1193*eda14cbcSMatt Macy >= efi_label->efi_last_lba && !sync_needed)) { 1194*eda14cbcSMatt Macy if (efi_debug) { 1195*eda14cbcSMatt Macy (void) fprintf(stderr, 1196*eda14cbcSMatt Macy "efi_use_whole_disk: requested space not found\n"); 1197*eda14cbcSMatt Macy } 1198*eda14cbcSMatt Macy efi_free(efi_label); 1199*eda14cbcSMatt Macy return (VT_ENOSPC); 1200*eda14cbcSMatt Macy } 1201*eda14cbcSMatt Macy 1202*eda14cbcSMatt Macy /* 1203*eda14cbcSMatt Macy * Verify that we've found the reserved partition by checking 1204*eda14cbcSMatt Macy * that it looks the way it did when we created it in zpool_label_disk. 1205*eda14cbcSMatt Macy * If we've found the incorrect partition, then we know that this 1206*eda14cbcSMatt Macy * device was reformatted and no longer is solely used by ZFS. 1207*eda14cbcSMatt Macy */ 1208*eda14cbcSMatt Macy if ((efi_label->efi_parts[resv_index].p_size != EFI_MIN_RESV_SIZE) || 1209*eda14cbcSMatt Macy (efi_label->efi_parts[resv_index].p_tag != V_RESERVED) || 1210*eda14cbcSMatt Macy (resv_index != 8)) { 1211*eda14cbcSMatt Macy if (efi_debug) { 1212*eda14cbcSMatt Macy (void) fprintf(stderr, 1213*eda14cbcSMatt Macy "efi_use_whole_disk: wholedisk not available\n"); 1214*eda14cbcSMatt Macy } 1215*eda14cbcSMatt Macy efi_free(efi_label); 1216*eda14cbcSMatt Macy return (VT_ENOSPC); 1217*eda14cbcSMatt Macy } 1218*eda14cbcSMatt Macy 1219*eda14cbcSMatt Macy if (data_start + data_size != resv_start) { 1220*eda14cbcSMatt Macy if (efi_debug) { 1221*eda14cbcSMatt Macy (void) fprintf(stderr, 1222*eda14cbcSMatt Macy "efi_use_whole_disk: " 1223*eda14cbcSMatt Macy "data_start (%lli) + " 1224*eda14cbcSMatt Macy "data_size (%lli) != " 1225*eda14cbcSMatt Macy "resv_start (%lli)\n", 1226*eda14cbcSMatt Macy data_start, data_size, resv_start); 1227*eda14cbcSMatt Macy } 1228*eda14cbcSMatt Macy 1229*eda14cbcSMatt Macy return (VT_EINVAL); 1230*eda14cbcSMatt Macy } 1231*eda14cbcSMatt Macy 1232*eda14cbcSMatt Macy if (limit < resv_start) { 1233*eda14cbcSMatt Macy if (efi_debug) { 1234*eda14cbcSMatt Macy (void) fprintf(stderr, 1235*eda14cbcSMatt Macy "efi_use_whole_disk: " 1236*eda14cbcSMatt Macy "limit (%lli) < resv_start (%lli)\n", 1237*eda14cbcSMatt Macy limit, resv_start); 1238*eda14cbcSMatt Macy } 1239*eda14cbcSMatt Macy 1240*eda14cbcSMatt Macy return (VT_EINVAL); 1241*eda14cbcSMatt Macy } 1242*eda14cbcSMatt Macy 1243*eda14cbcSMatt Macy difference = limit - resv_start; 1244*eda14cbcSMatt Macy 1245*eda14cbcSMatt Macy if (efi_debug) 1246*eda14cbcSMatt Macy (void) fprintf(stderr, 1247*eda14cbcSMatt Macy "efi_use_whole_disk: difference is %lli\n", difference); 1248*eda14cbcSMatt Macy 1249*eda14cbcSMatt Macy /* 1250*eda14cbcSMatt Macy * Move the reserved partition. There is currently no data in 1251*eda14cbcSMatt Macy * here except fabricated devids (which get generated via 1252*eda14cbcSMatt Macy * efi_write()). So there is no need to copy data. 1253*eda14cbcSMatt Macy */ 1254*eda14cbcSMatt Macy efi_label->efi_parts[data_index].p_size += difference; 1255*eda14cbcSMatt Macy efi_label->efi_parts[resv_index].p_start += difference; 1256*eda14cbcSMatt Macy efi_label->efi_last_u_lba = efi_label->efi_last_lba - nblocks; 1257*eda14cbcSMatt Macy 1258*eda14cbcSMatt Macy rval = efi_write(fd, efi_label); 1259*eda14cbcSMatt Macy if (rval < 0) { 1260*eda14cbcSMatt Macy if (efi_debug) { 1261*eda14cbcSMatt Macy (void) fprintf(stderr, 1262*eda14cbcSMatt Macy "efi_use_whole_disk:fail to write label, rval=%d\n", 1263*eda14cbcSMatt Macy rval); 1264*eda14cbcSMatt Macy } 1265*eda14cbcSMatt Macy efi_free(efi_label); 1266*eda14cbcSMatt Macy return (rval); 1267*eda14cbcSMatt Macy } 1268*eda14cbcSMatt Macy 1269*eda14cbcSMatt Macy efi_free(efi_label); 1270*eda14cbcSMatt Macy return (0); 1271*eda14cbcSMatt Macy } 1272*eda14cbcSMatt Macy 1273*eda14cbcSMatt Macy /* 1274*eda14cbcSMatt Macy * write EFI label and backup label 1275*eda14cbcSMatt Macy */ 1276*eda14cbcSMatt Macy int 1277*eda14cbcSMatt Macy efi_write(int fd, struct dk_gpt *vtoc) 1278*eda14cbcSMatt Macy { 1279*eda14cbcSMatt Macy dk_efi_t dk_ioc; 1280*eda14cbcSMatt Macy efi_gpt_t *efi; 1281*eda14cbcSMatt Macy efi_gpe_t *efi_parts; 1282*eda14cbcSMatt Macy int i, j; 1283*eda14cbcSMatt Macy struct dk_cinfo dki_info; 1284*eda14cbcSMatt Macy int rval; 1285*eda14cbcSMatt Macy int md_flag = 0; 1286*eda14cbcSMatt Macy int nblocks; 1287*eda14cbcSMatt Macy diskaddr_t lba_backup_gpt_hdr; 1288*eda14cbcSMatt Macy 1289*eda14cbcSMatt Macy if ((rval = efi_get_info(fd, &dki_info)) != 0) 1290*eda14cbcSMatt Macy return (rval); 1291*eda14cbcSMatt Macy 1292*eda14cbcSMatt Macy /* check if we are dealing with a metadevice */ 1293*eda14cbcSMatt Macy if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) && 1294*eda14cbcSMatt Macy (strncmp(dki_info.dki_dname, "md", 3) == 0)) { 1295*eda14cbcSMatt Macy md_flag = 1; 1296*eda14cbcSMatt Macy } 1297*eda14cbcSMatt Macy 1298*eda14cbcSMatt Macy if (check_input(vtoc)) { 1299*eda14cbcSMatt Macy /* 1300*eda14cbcSMatt Macy * not valid; if it's a metadevice just pass it down 1301*eda14cbcSMatt Macy * because SVM will do its own checking 1302*eda14cbcSMatt Macy */ 1303*eda14cbcSMatt Macy if (md_flag == 0) { 1304*eda14cbcSMatt Macy return (VT_EINVAL); 1305*eda14cbcSMatt Macy } 1306*eda14cbcSMatt Macy } 1307*eda14cbcSMatt Macy 1308*eda14cbcSMatt Macy dk_ioc.dki_lba = 1; 1309*eda14cbcSMatt Macy if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) { 1310*eda14cbcSMatt Macy dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize; 1311*eda14cbcSMatt Macy } else { 1312*eda14cbcSMatt Macy dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts, 1313*eda14cbcSMatt Macy vtoc->efi_lbasize) * 1314*eda14cbcSMatt Macy vtoc->efi_lbasize; 1315*eda14cbcSMatt Macy } 1316*eda14cbcSMatt Macy 1317*eda14cbcSMatt Macy /* 1318*eda14cbcSMatt Macy * the number of blocks occupied by GUID partition entry array 1319*eda14cbcSMatt Macy */ 1320*eda14cbcSMatt Macy nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1; 1321*eda14cbcSMatt Macy 1322*eda14cbcSMatt Macy /* 1323*eda14cbcSMatt Macy * Backup GPT header is located on the block after GUID 1324*eda14cbcSMatt Macy * partition entry array. Here, we calculate the address 1325*eda14cbcSMatt Macy * for backup GPT header. 1326*eda14cbcSMatt Macy */ 1327*eda14cbcSMatt Macy lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks; 1328*eda14cbcSMatt Macy if (posix_memalign((void **)&dk_ioc.dki_data, 1329*eda14cbcSMatt Macy vtoc->efi_lbasize, dk_ioc.dki_length)) 1330*eda14cbcSMatt Macy return (VT_ERROR); 1331*eda14cbcSMatt Macy 1332*eda14cbcSMatt Macy memset(dk_ioc.dki_data, 0, dk_ioc.dki_length); 1333*eda14cbcSMatt Macy efi = dk_ioc.dki_data; 1334*eda14cbcSMatt Macy 1335*eda14cbcSMatt Macy /* stuff user's input into EFI struct */ 1336*eda14cbcSMatt Macy efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE); 1337*eda14cbcSMatt Macy efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */ 1338*eda14cbcSMatt Macy efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt) - LEN_EFI_PAD); 1339*eda14cbcSMatt Macy efi->efi_gpt_Reserved1 = 0; 1340*eda14cbcSMatt Macy efi->efi_gpt_MyLBA = LE_64(1ULL); 1341*eda14cbcSMatt Macy efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr); 1342*eda14cbcSMatt Macy efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba); 1343*eda14cbcSMatt Macy efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba); 1344*eda14cbcSMatt Macy efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL); 1345*eda14cbcSMatt Macy efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts); 1346*eda14cbcSMatt Macy efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe)); 1347*eda14cbcSMatt Macy UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid); 1348*eda14cbcSMatt Macy 1349*eda14cbcSMatt Macy /* LINTED -- always longlong aligned */ 1350*eda14cbcSMatt Macy efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize); 1351*eda14cbcSMatt Macy 1352*eda14cbcSMatt Macy for (i = 0; i < vtoc->efi_nparts; i++) { 1353*eda14cbcSMatt Macy for (j = 0; 1354*eda14cbcSMatt Macy j < sizeof (conversion_array) / 1355*eda14cbcSMatt Macy sizeof (struct uuid_to_ptag); j++) { 1356*eda14cbcSMatt Macy 1357*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == j) { 1358*eda14cbcSMatt Macy UUID_LE_CONVERT( 1359*eda14cbcSMatt Macy efi_parts[i].efi_gpe_PartitionTypeGUID, 1360*eda14cbcSMatt Macy conversion_array[j].uuid); 1361*eda14cbcSMatt Macy break; 1362*eda14cbcSMatt Macy } 1363*eda14cbcSMatt Macy } 1364*eda14cbcSMatt Macy 1365*eda14cbcSMatt Macy if (j == sizeof (conversion_array) / 1366*eda14cbcSMatt Macy sizeof (struct uuid_to_ptag)) { 1367*eda14cbcSMatt Macy /* 1368*eda14cbcSMatt Macy * If we didn't have a matching uuid match, bail here. 1369*eda14cbcSMatt Macy * Don't write a label with unknown uuid. 1370*eda14cbcSMatt Macy */ 1371*eda14cbcSMatt Macy if (efi_debug) { 1372*eda14cbcSMatt Macy (void) fprintf(stderr, 1373*eda14cbcSMatt Macy "Unknown uuid for p_tag %d\n", 1374*eda14cbcSMatt Macy vtoc->efi_parts[i].p_tag); 1375*eda14cbcSMatt Macy } 1376*eda14cbcSMatt Macy return (VT_EINVAL); 1377*eda14cbcSMatt Macy } 1378*eda14cbcSMatt Macy 1379*eda14cbcSMatt Macy /* Zero's should be written for empty partitions */ 1380*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) 1381*eda14cbcSMatt Macy continue; 1382*eda14cbcSMatt Macy 1383*eda14cbcSMatt Macy efi_parts[i].efi_gpe_StartingLBA = 1384*eda14cbcSMatt Macy LE_64(vtoc->efi_parts[i].p_start); 1385*eda14cbcSMatt Macy efi_parts[i].efi_gpe_EndingLBA = 1386*eda14cbcSMatt Macy LE_64(vtoc->efi_parts[i].p_start + 1387*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size - 1); 1388*eda14cbcSMatt Macy efi_parts[i].efi_gpe_Attributes.PartitionAttrs = 1389*eda14cbcSMatt Macy LE_16(vtoc->efi_parts[i].p_flag); 1390*eda14cbcSMatt Macy for (j = 0; j < EFI_PART_NAME_LEN; j++) { 1391*eda14cbcSMatt Macy efi_parts[i].efi_gpe_PartitionName[j] = 1392*eda14cbcSMatt Macy LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]); 1393*eda14cbcSMatt Macy } 1394*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) && 1395*eda14cbcSMatt Macy uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) { 1396*eda14cbcSMatt Macy (void) uuid_generate((uchar_t *) 1397*eda14cbcSMatt Macy &vtoc->efi_parts[i].p_uguid); 1398*eda14cbcSMatt Macy } 1399*eda14cbcSMatt Macy bcopy(&vtoc->efi_parts[i].p_uguid, 1400*eda14cbcSMatt Macy &efi_parts[i].efi_gpe_UniquePartitionGUID, 1401*eda14cbcSMatt Macy sizeof (uuid_t)); 1402*eda14cbcSMatt Macy } 1403*eda14cbcSMatt Macy efi->efi_gpt_PartitionEntryArrayCRC32 = 1404*eda14cbcSMatt Macy LE_32(efi_crc32((unsigned char *)efi_parts, 1405*eda14cbcSMatt Macy vtoc->efi_nparts * (int)sizeof (struct efi_gpe))); 1406*eda14cbcSMatt Macy efi->efi_gpt_HeaderCRC32 = 1407*eda14cbcSMatt Macy LE_32(efi_crc32((unsigned char *)efi, 1408*eda14cbcSMatt Macy LE_32(efi->efi_gpt_HeaderSize))); 1409*eda14cbcSMatt Macy 1410*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { 1411*eda14cbcSMatt Macy free(dk_ioc.dki_data); 1412*eda14cbcSMatt Macy switch (errno) { 1413*eda14cbcSMatt Macy case EIO: 1414*eda14cbcSMatt Macy return (VT_EIO); 1415*eda14cbcSMatt Macy case EINVAL: 1416*eda14cbcSMatt Macy return (VT_EINVAL); 1417*eda14cbcSMatt Macy default: 1418*eda14cbcSMatt Macy return (VT_ERROR); 1419*eda14cbcSMatt Macy } 1420*eda14cbcSMatt Macy } 1421*eda14cbcSMatt Macy /* if it's a metadevice we're done */ 1422*eda14cbcSMatt Macy if (md_flag) { 1423*eda14cbcSMatt Macy free(dk_ioc.dki_data); 1424*eda14cbcSMatt Macy return (0); 1425*eda14cbcSMatt Macy } 1426*eda14cbcSMatt Macy 1427*eda14cbcSMatt Macy /* write backup partition array */ 1428*eda14cbcSMatt Macy dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1; 1429*eda14cbcSMatt Macy dk_ioc.dki_length -= vtoc->efi_lbasize; 1430*eda14cbcSMatt Macy /* LINTED */ 1431*eda14cbcSMatt Macy dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data + 1432*eda14cbcSMatt Macy vtoc->efi_lbasize); 1433*eda14cbcSMatt Macy 1434*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { 1435*eda14cbcSMatt Macy /* 1436*eda14cbcSMatt Macy * we wrote the primary label okay, so don't fail 1437*eda14cbcSMatt Macy */ 1438*eda14cbcSMatt Macy if (efi_debug) { 1439*eda14cbcSMatt Macy (void) fprintf(stderr, 1440*eda14cbcSMatt Macy "write of backup partitions to block %llu " 1441*eda14cbcSMatt Macy "failed, errno %d\n", 1442*eda14cbcSMatt Macy vtoc->efi_last_u_lba + 1, 1443*eda14cbcSMatt Macy errno); 1444*eda14cbcSMatt Macy } 1445*eda14cbcSMatt Macy } 1446*eda14cbcSMatt Macy /* 1447*eda14cbcSMatt Macy * now swap MyLBA and AlternateLBA fields and write backup 1448*eda14cbcSMatt Macy * partition table header 1449*eda14cbcSMatt Macy */ 1450*eda14cbcSMatt Macy dk_ioc.dki_lba = lba_backup_gpt_hdr; 1451*eda14cbcSMatt Macy dk_ioc.dki_length = vtoc->efi_lbasize; 1452*eda14cbcSMatt Macy /* LINTED */ 1453*eda14cbcSMatt Macy dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data - 1454*eda14cbcSMatt Macy vtoc->efi_lbasize); 1455*eda14cbcSMatt Macy efi->efi_gpt_AlternateLBA = LE_64(1ULL); 1456*eda14cbcSMatt Macy efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr); 1457*eda14cbcSMatt Macy efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1); 1458*eda14cbcSMatt Macy efi->efi_gpt_HeaderCRC32 = 0; 1459*eda14cbcSMatt Macy efi->efi_gpt_HeaderCRC32 = 1460*eda14cbcSMatt Macy LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data, 1461*eda14cbcSMatt Macy LE_32(efi->efi_gpt_HeaderSize))); 1462*eda14cbcSMatt Macy 1463*eda14cbcSMatt Macy if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { 1464*eda14cbcSMatt Macy if (efi_debug) { 1465*eda14cbcSMatt Macy (void) fprintf(stderr, 1466*eda14cbcSMatt Macy "write of backup header to block %llu failed, " 1467*eda14cbcSMatt Macy "errno %d\n", 1468*eda14cbcSMatt Macy lba_backup_gpt_hdr, 1469*eda14cbcSMatt Macy errno); 1470*eda14cbcSMatt Macy } 1471*eda14cbcSMatt Macy } 1472*eda14cbcSMatt Macy /* write the PMBR */ 1473*eda14cbcSMatt Macy (void) write_pmbr(fd, vtoc); 1474*eda14cbcSMatt Macy free(dk_ioc.dki_data); 1475*eda14cbcSMatt Macy 1476*eda14cbcSMatt Macy return (0); 1477*eda14cbcSMatt Macy } 1478*eda14cbcSMatt Macy 1479*eda14cbcSMatt Macy void 1480*eda14cbcSMatt Macy efi_free(struct dk_gpt *ptr) 1481*eda14cbcSMatt Macy { 1482*eda14cbcSMatt Macy free(ptr); 1483*eda14cbcSMatt Macy } 1484*eda14cbcSMatt Macy 1485*eda14cbcSMatt Macy /* 1486*eda14cbcSMatt Macy * Input: File descriptor 1487*eda14cbcSMatt Macy * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR. 1488*eda14cbcSMatt Macy * Otherwise 0. 1489*eda14cbcSMatt Macy */ 1490*eda14cbcSMatt Macy int 1491*eda14cbcSMatt Macy efi_type(int fd) 1492*eda14cbcSMatt Macy { 1493*eda14cbcSMatt Macy #if 0 1494*eda14cbcSMatt Macy struct vtoc vtoc; 1495*eda14cbcSMatt Macy struct extvtoc extvtoc; 1496*eda14cbcSMatt Macy 1497*eda14cbcSMatt Macy if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) { 1498*eda14cbcSMatt Macy if (errno == ENOTSUP) 1499*eda14cbcSMatt Macy return (1); 1500*eda14cbcSMatt Macy else if (errno == ENOTTY) { 1501*eda14cbcSMatt Macy if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1) 1502*eda14cbcSMatt Macy if (errno == ENOTSUP) 1503*eda14cbcSMatt Macy return (1); 1504*eda14cbcSMatt Macy } 1505*eda14cbcSMatt Macy } 1506*eda14cbcSMatt Macy return (0); 1507*eda14cbcSMatt Macy #else 1508*eda14cbcSMatt Macy return (ENOSYS); 1509*eda14cbcSMatt Macy #endif 1510*eda14cbcSMatt Macy } 1511*eda14cbcSMatt Macy 1512*eda14cbcSMatt Macy void 1513*eda14cbcSMatt Macy efi_err_check(struct dk_gpt *vtoc) 1514*eda14cbcSMatt Macy { 1515*eda14cbcSMatt Macy int resv_part = -1; 1516*eda14cbcSMatt Macy int i, j; 1517*eda14cbcSMatt Macy diskaddr_t istart, jstart, isize, jsize, endsect; 1518*eda14cbcSMatt Macy int overlap = 0; 1519*eda14cbcSMatt Macy 1520*eda14cbcSMatt Macy /* 1521*eda14cbcSMatt Macy * make sure no partitions overlap 1522*eda14cbcSMatt Macy */ 1523*eda14cbcSMatt Macy for (i = 0; i < vtoc->efi_nparts; i++) { 1524*eda14cbcSMatt Macy /* It can't be unassigned and have an actual size */ 1525*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) && 1526*eda14cbcSMatt Macy (vtoc->efi_parts[i].p_size != 0)) { 1527*eda14cbcSMatt Macy (void) fprintf(stderr, 1528*eda14cbcSMatt Macy "partition %d is \"unassigned\" but has a size " 1529*eda14cbcSMatt Macy "of %llu\n", i, vtoc->efi_parts[i].p_size); 1530*eda14cbcSMatt Macy } 1531*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) { 1532*eda14cbcSMatt Macy continue; 1533*eda14cbcSMatt Macy } 1534*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_tag == V_RESERVED) { 1535*eda14cbcSMatt Macy if (resv_part != -1) { 1536*eda14cbcSMatt Macy (void) fprintf(stderr, 1537*eda14cbcSMatt Macy "found duplicate reserved partition at " 1538*eda14cbcSMatt Macy "%d\n", i); 1539*eda14cbcSMatt Macy } 1540*eda14cbcSMatt Macy resv_part = i; 1541*eda14cbcSMatt Macy if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE) 1542*eda14cbcSMatt Macy (void) fprintf(stderr, 1543*eda14cbcSMatt Macy "Warning: reserved partition size must " 1544*eda14cbcSMatt Macy "be %d sectors\n", EFI_MIN_RESV_SIZE); 1545*eda14cbcSMatt Macy } 1546*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) || 1547*eda14cbcSMatt Macy (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) { 1548*eda14cbcSMatt Macy (void) fprintf(stderr, 1549*eda14cbcSMatt Macy "Partition %d starts at %llu\n", 1550*eda14cbcSMatt Macy i, 1551*eda14cbcSMatt Macy vtoc->efi_parts[i].p_start); 1552*eda14cbcSMatt Macy (void) fprintf(stderr, 1553*eda14cbcSMatt Macy "It must be between %llu and %llu.\n", 1554*eda14cbcSMatt Macy vtoc->efi_first_u_lba, 1555*eda14cbcSMatt Macy vtoc->efi_last_u_lba); 1556*eda14cbcSMatt Macy } 1557*eda14cbcSMatt Macy if ((vtoc->efi_parts[i].p_start + 1558*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size < 1559*eda14cbcSMatt Macy vtoc->efi_first_u_lba) || 1560*eda14cbcSMatt Macy (vtoc->efi_parts[i].p_start + 1561*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size > 1562*eda14cbcSMatt Macy vtoc->efi_last_u_lba + 1)) { 1563*eda14cbcSMatt Macy (void) fprintf(stderr, 1564*eda14cbcSMatt Macy "Partition %d ends at %llu\n", 1565*eda14cbcSMatt Macy i, 1566*eda14cbcSMatt Macy vtoc->efi_parts[i].p_start + 1567*eda14cbcSMatt Macy vtoc->efi_parts[i].p_size); 1568*eda14cbcSMatt Macy (void) fprintf(stderr, 1569*eda14cbcSMatt Macy "It must be between %llu and %llu.\n", 1570*eda14cbcSMatt Macy vtoc->efi_first_u_lba, 1571*eda14cbcSMatt Macy vtoc->efi_last_u_lba); 1572*eda14cbcSMatt Macy } 1573*eda14cbcSMatt Macy 1574*eda14cbcSMatt Macy for (j = 0; j < vtoc->efi_nparts; j++) { 1575*eda14cbcSMatt Macy isize = vtoc->efi_parts[i].p_size; 1576*eda14cbcSMatt Macy jsize = vtoc->efi_parts[j].p_size; 1577*eda14cbcSMatt Macy istart = vtoc->efi_parts[i].p_start; 1578*eda14cbcSMatt Macy jstart = vtoc->efi_parts[j].p_start; 1579*eda14cbcSMatt Macy if ((i != j) && (isize != 0) && (jsize != 0)) { 1580*eda14cbcSMatt Macy endsect = jstart + jsize -1; 1581*eda14cbcSMatt Macy if ((jstart <= istart) && 1582*eda14cbcSMatt Macy (istart <= endsect)) { 1583*eda14cbcSMatt Macy if (!overlap) { 1584*eda14cbcSMatt Macy (void) fprintf(stderr, 1585*eda14cbcSMatt Macy "label error: EFI Labels do not " 1586*eda14cbcSMatt Macy "support overlapping partitions\n"); 1587*eda14cbcSMatt Macy } 1588*eda14cbcSMatt Macy (void) fprintf(stderr, 1589*eda14cbcSMatt Macy "Partition %d overlaps partition " 1590*eda14cbcSMatt Macy "%d.\n", i, j); 1591*eda14cbcSMatt Macy overlap = 1; 1592*eda14cbcSMatt Macy } 1593*eda14cbcSMatt Macy } 1594*eda14cbcSMatt Macy } 1595*eda14cbcSMatt Macy } 1596*eda14cbcSMatt Macy /* make sure there is a reserved partition */ 1597*eda14cbcSMatt Macy if (resv_part == -1) { 1598*eda14cbcSMatt Macy (void) fprintf(stderr, 1599*eda14cbcSMatt Macy "no reserved partition found\n"); 1600*eda14cbcSMatt Macy } 1601*eda14cbcSMatt Macy } 1602*eda14cbcSMatt Macy 1603*eda14cbcSMatt Macy /* 1604*eda14cbcSMatt Macy * We need to get information necessary to construct a *new* efi 1605*eda14cbcSMatt Macy * label type 1606*eda14cbcSMatt Macy */ 1607*eda14cbcSMatt Macy int 1608*eda14cbcSMatt Macy efi_auto_sense(int fd, struct dk_gpt **vtoc) 1609*eda14cbcSMatt Macy { 1610*eda14cbcSMatt Macy 1611*eda14cbcSMatt Macy int i; 1612*eda14cbcSMatt Macy 1613*eda14cbcSMatt Macy /* 1614*eda14cbcSMatt Macy * Now build the default partition table 1615*eda14cbcSMatt Macy */ 1616*eda14cbcSMatt Macy if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) { 1617*eda14cbcSMatt Macy if (efi_debug) { 1618*eda14cbcSMatt Macy (void) fprintf(stderr, "efi_alloc_and_init failed.\n"); 1619*eda14cbcSMatt Macy } 1620*eda14cbcSMatt Macy return (-1); 1621*eda14cbcSMatt Macy } 1622*eda14cbcSMatt Macy 1623*eda14cbcSMatt Macy for (i = 0; i < MIN((*vtoc)->efi_nparts, V_NUMPAR); i++) { 1624*eda14cbcSMatt Macy (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag; 1625*eda14cbcSMatt Macy (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag; 1626*eda14cbcSMatt Macy (*vtoc)->efi_parts[i].p_start = 0; 1627*eda14cbcSMatt Macy (*vtoc)->efi_parts[i].p_size = 0; 1628*eda14cbcSMatt Macy } 1629*eda14cbcSMatt Macy /* 1630*eda14cbcSMatt Macy * Make constants first 1631*eda14cbcSMatt Macy * and variable partitions later 1632*eda14cbcSMatt Macy */ 1633*eda14cbcSMatt Macy 1634*eda14cbcSMatt Macy /* root partition - s0 128 MB */ 1635*eda14cbcSMatt Macy (*vtoc)->efi_parts[0].p_start = 34; 1636*eda14cbcSMatt Macy (*vtoc)->efi_parts[0].p_size = 262144; 1637*eda14cbcSMatt Macy 1638*eda14cbcSMatt Macy /* partition - s1 128 MB */ 1639*eda14cbcSMatt Macy (*vtoc)->efi_parts[1].p_start = 262178; 1640*eda14cbcSMatt Macy (*vtoc)->efi_parts[1].p_size = 262144; 1641*eda14cbcSMatt Macy 1642*eda14cbcSMatt Macy /* partition -s2 is NOT the Backup disk */ 1643*eda14cbcSMatt Macy (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED; 1644*eda14cbcSMatt Macy 1645*eda14cbcSMatt Macy /* partition -s6 /usr partition - HOG */ 1646*eda14cbcSMatt Macy (*vtoc)->efi_parts[6].p_start = 524322; 1647*eda14cbcSMatt Macy (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322 1648*eda14cbcSMatt Macy - (1024 * 16); 1649*eda14cbcSMatt Macy 1650*eda14cbcSMatt Macy /* efi reserved partition - s9 16K */ 1651*eda14cbcSMatt Macy (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16); 1652*eda14cbcSMatt Macy (*vtoc)->efi_parts[8].p_size = (1024 * 16); 1653*eda14cbcSMatt Macy (*vtoc)->efi_parts[8].p_tag = V_RESERVED; 1654*eda14cbcSMatt Macy return (0); 1655*eda14cbcSMatt Macy } 1656