1324709Simp/*- 2324709Simp * Copyright (c) 2015 Eric McCorkle 3324709Simp * All rights reserved. 4324709Simp * 5324709Simp * Redistribution and use in source and binary forms, with or without 6324709Simp * modification, are permitted provided that the following conditions 7324709Simp * are met: 8324709Simp * 1. Redistributions of source code must retain the above copyright 9324709Simp * notice, this list of conditions and the following disclaimer. 10324709Simp * 2. Redistributions in binary form must reproduce the above copyright 11324709Simp * notice, this list of conditions and the following disclaimer in the 12324709Simp * documentation and/or other materials provided with the distribution. 13324709Simp * 14324709Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15324709Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16324709Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17324709Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18324709Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19324709Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20324709Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21324709Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22324709Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23324709Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24324709Simp * SUCH DAMAGE. 25324709Simp * 26324709Simp * $FreeBSD: stable/11/stand/efi/boot1/zfs_module.c 329140 2018-02-11 20:58:00Z kevans $ 27324709Simp */ 28324709Simp#include <stddef.h> 29324709Simp#include <stdarg.h> 30324709Simp#include <stdbool.h> 31324709Simp#include <sys/cdefs.h> 32324709Simp#include <sys/param.h> 33324709Simp#include <sys/queue.h> 34324709Simp#include <efi.h> 35324709Simp 36324709Simp#include "boot_module.h" 37324709Simp 38324709Simp#include "libzfs.h" 39324709Simp#include "zfsimpl.c" 40324709Simp 41324709Simpstatic dev_info_t *devices; 42324709Simp 43324709Simpuint64_t 44324709Simpldi_get_size(void *priv) 45324709Simp{ 46324709Simp dev_info_t *devinfo = priv; 47324709Simp 48324709Simp return (devinfo->dev->Media->BlockSize * 49324709Simp (devinfo->dev->Media->LastBlock + 1)); 50324709Simp} 51324709Simp 52324709Simpstatic int 53324709Simpvdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) 54324709Simp{ 55324709Simp dev_info_t *devinfo; 56324709Simp uint64_t lba; 57324709Simp size_t size, remainder, rb_size, blksz; 58324709Simp char *bouncebuf = NULL, *rb_buf; 59324709Simp EFI_STATUS status; 60324709Simp 61324709Simp devinfo = (dev_info_t *)priv; 62324709Simp lba = off / devinfo->dev->Media->BlockSize; 63324709Simp remainder = off % devinfo->dev->Media->BlockSize; 64324709Simp 65324709Simp rb_buf = buf; 66324709Simp rb_size = bytes; 67324709Simp 68324709Simp /* 69324709Simp * If we have remainder from off, we need to add remainder part. 70324709Simp * Since buffer must be multiple of the BlockSize, round it all up. 71324709Simp */ 72324709Simp size = roundup2(bytes + remainder, devinfo->dev->Media->BlockSize); 73324709Simp blksz = size; 74324709Simp if (remainder != 0 || size != bytes) { 75324709Simp rb_size = devinfo->dev->Media->BlockSize; 76324709Simp bouncebuf = malloc(rb_size); 77324709Simp if (bouncebuf == NULL) { 78324709Simp printf("vdev_read: out of memory\n"); 79324709Simp return (-1); 80324709Simp } 81324709Simp rb_buf = bouncebuf; 82324709Simp blksz = rb_size - remainder; 83324709Simp } 84324709Simp 85324709Simp while (bytes > 0) { 86324709Simp status = devinfo->dev->ReadBlocks(devinfo->dev, 87324709Simp devinfo->dev->Media->MediaId, lba, rb_size, rb_buf); 88324709Simp if (EFI_ERROR(status)) 89324709Simp goto error; 90324709Simp if (bytes < blksz) 91324709Simp blksz = bytes; 92324709Simp if (bouncebuf != NULL) 93324709Simp memcpy(buf, rb_buf + remainder, blksz); 94324709Simp buf = (void *)((uintptr_t)buf + blksz); 95324709Simp bytes -= blksz; 96324709Simp lba++; 97324709Simp remainder = 0; 98324709Simp blksz = rb_size; 99324709Simp } 100324709Simp 101324709Simp free(bouncebuf); 102324709Simp return (0); 103324709Simp 104324709Simperror: 105324709Simp free(bouncebuf); 106324709Simp DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %ju, size: %zu," 107324709Simp " rb_size: %zu, status: %lu\n", devinfo->dev, 108324709Simp devinfo->dev->Media->MediaId, (uintmax_t)lba, bytes, rb_size, 109324709Simp EFI_ERROR_CODE(status)); 110324709Simp return (-1); 111324709Simp} 112324709Simp 113324709Simpstatic EFI_STATUS 114324709Simpprobe(dev_info_t *dev) 115324709Simp{ 116324709Simp spa_t *spa; 117324709Simp dev_info_t *tdev; 118324709Simp EFI_STATUS status; 119324709Simp 120324709Simp /* ZFS consumes the dev on success so we need a copy. */ 121324709Simp if ((status = BS->AllocatePool(EfiLoaderData, sizeof(*dev), 122324709Simp (void**)&tdev)) != EFI_SUCCESS) { 123324709Simp DPRINTF("Failed to allocate tdev (%lu)\n", 124324709Simp EFI_ERROR_CODE(status)); 125324709Simp return (status); 126324709Simp } 127324709Simp memcpy(tdev, dev, sizeof(*dev)); 128324709Simp 129324709Simp if (vdev_probe(vdev_read, tdev, &spa) != 0) { 130324709Simp (void)BS->FreePool(tdev); 131324709Simp return (EFI_UNSUPPORTED); 132324709Simp } 133324709Simp 134324709Simp dev->devdata = spa; 135324709Simp add_device(&devices, dev); 136324709Simp 137324709Simp return (EFI_SUCCESS); 138324709Simp} 139324709Simp 140324709Simpstatic EFI_STATUS 141324709Simpload(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize) 142324709Simp{ 143324709Simp spa_t *spa; 144324709Simp struct zfsmount zfsmount; 145324709Simp dnode_phys_t dn; 146324709Simp struct stat st; 147324709Simp int err; 148324709Simp void *buf; 149324709Simp EFI_STATUS status; 150324709Simp 151324709Simp spa = devinfo->devdata; 152324709Simp 153324709Simp#ifdef EFI_DEBUG 154324709Simp { 155324709Simp CHAR16 *text = efi_devpath_name(devinfo->devpath); 156324709Simp DPRINTF("load: '%s' spa: '%s', devpath: %S\n", filepath, 157324709Simp spa->spa_name, text); 158324709Simp efi_free_devpath_name(text); 159324709Simp } 160324709Simp#endif 161324709Simp if ((err = zfs_spa_init(spa)) != 0) { 162324709Simp DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err); 163324709Simp return (EFI_NOT_FOUND); 164324709Simp } 165324709Simp 166324709Simp if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) { 167324709Simp DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err); 168324709Simp return (EFI_NOT_FOUND); 169324709Simp } 170324709Simp 171324709Simp if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) { 172324709Simp if (err == ENOENT) { 173324709Simp DPRINTF("Failed to find '%s' on pool '%s' (%d)\n", 174324709Simp filepath, spa->spa_name, err); 175324709Simp return (EFI_NOT_FOUND); 176324709Simp } 177324709Simp printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath, 178324709Simp spa->spa_name, err); 179324709Simp return (EFI_INVALID_PARAMETER); 180324709Simp } 181324709Simp 182324709Simp if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) { 183324709Simp printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath, 184324709Simp spa->spa_name, err); 185324709Simp return (EFI_INVALID_PARAMETER); 186324709Simp } 187324709Simp 188324709Simp if ((status = BS->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf)) 189324709Simp != EFI_SUCCESS) { 190324709Simp printf("Failed to allocate load buffer %jd for pool '%s' for '%s' " 191324709Simp "(%lu)\n", (intmax_t)st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status)); 192324709Simp return (EFI_INVALID_PARAMETER); 193324709Simp } 194324709Simp 195324709Simp if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) { 196324709Simp printf("Failed to read node from %s (%d)\n", spa->spa_name, 197324709Simp err); 198324709Simp (void)BS->FreePool(buf); 199324709Simp return (EFI_INVALID_PARAMETER); 200324709Simp } 201324709Simp 202324709Simp *bufsize = st.st_size; 203324709Simp *bufp = buf; 204324709Simp 205324709Simp return (EFI_SUCCESS); 206324709Simp} 207324709Simp 208324709Simpstatic void 209324709Simpstatus(void) 210324709Simp{ 211324709Simp spa_t *spa; 212324709Simp 213324709Simp spa = STAILQ_FIRST(&zfs_pools); 214324709Simp if (spa == NULL) { 215324709Simp printf("%s found no pools\n", zfs_module.name); 216324709Simp return; 217324709Simp } 218324709Simp 219324709Simp printf("%s found the following pools:", zfs_module.name); 220324709Simp STAILQ_FOREACH(spa, &zfs_pools, spa_link) 221324709Simp printf(" %s", spa->spa_name); 222324709Simp 223324709Simp printf("\n"); 224324709Simp} 225324709Simp 226324709Simpstatic void 227324709Simpinit(void) 228324709Simp{ 229324709Simp 230324709Simp zfs_init(); 231324709Simp} 232324709Simp 233324709Simpstatic dev_info_t * 234324709Simp_devices(void) 235324709Simp{ 236324709Simp 237324709Simp return (devices); 238324709Simp} 239324709Simp 240324709Simpconst boot_module_t zfs_module = 241324709Simp{ 242324709Simp .name = "ZFS", 243324709Simp .init = init, 244324709Simp .probe = probe, 245324709Simp .load = load, 246324709Simp .status = status, 247324709Simp .devices = _devices 248324709Simp}; 249