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