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