1201941Smarcel/*- 2201941Smarcel * Copyright (c) 2010 Marcel Moolenaar 3201941Smarcel * All rights reserved. 4201941Smarcel * 5201941Smarcel * Redistribution and use in source and binary forms, with or without 6201941Smarcel * modification, are permitted provided that the following conditions 7201941Smarcel * are met: 8201941Smarcel * 1. Redistributions of source code must retain the above copyright 9201941Smarcel * notice, this list of conditions and the following disclaimer. 10201941Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11201941Smarcel * notice, this list of conditions and the following disclaimer in the 12201941Smarcel * documentation and/or other materials provided with the distribution. 13201941Smarcel * 14201941Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15201941Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16201941Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17201941Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18201941Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19201941Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20201941Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21201941Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22201941Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23201941Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24201941Smarcel * SUCH DAMAGE. 25201941Smarcel */ 26201941Smarcel 27201941Smarcel#include <sys/cdefs.h> 28201941Smarcel__FBSDID("$FreeBSD$"); 29201941Smarcel 30201941Smarcel#include <sys/param.h> 31201941Smarcel#include <sys/time.h> 32201941Smarcel#include <stddef.h> 33201941Smarcel#include <stdarg.h> 34201941Smarcel 35201941Smarcel#include <bootstrap.h> 36201941Smarcel 37201941Smarcel#include <efi.h> 38201941Smarcel#include <efilib.h> 39201941Smarcel#include <efiprot.h> 40201941Smarcel 41201941Smarcelstatic EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 42201941Smarcel 43201941Smarcelstatic int efipart_init(void); 44201941Smarcelstatic int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); 45201941Smarcelstatic int efipart_open(struct open_file *, ...); 46201941Smarcelstatic int efipart_close(struct open_file *); 47201941Smarcelstatic void efipart_print(int); 48201941Smarcel 49201941Smarcelstruct devsw efipart_dev = { 50201941Smarcel .dv_name = "part", 51201941Smarcel .dv_type = DEVT_DISK, 52201941Smarcel .dv_init = efipart_init, 53201941Smarcel .dv_strategy = efipart_strategy, 54201941Smarcel .dv_open = efipart_open, 55201941Smarcel .dv_close = efipart_close, 56201941Smarcel .dv_ioctl = noioctl, 57201941Smarcel .dv_print = efipart_print, 58201941Smarcel .dv_cleanup = NULL 59201941Smarcel}; 60201941Smarcel 61201941Smarcelstatic int 62201941Smarcelefipart_init(void) 63201941Smarcel{ 64201941Smarcel EFI_BLOCK_IO *blkio; 65201941Smarcel EFI_HANDLE *hin, *hout; 66201941Smarcel EFI_STATUS status; 67201941Smarcel UINTN sz; 68201941Smarcel u_int n, nin, nout; 69201941Smarcel int err; 70201941Smarcel 71201941Smarcel sz = 0; 72217067Smarcel hin = NULL; 73201941Smarcel status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); 74201941Smarcel if (status == EFI_BUFFER_TOO_SMALL) { 75201941Smarcel hin = (EFI_HANDLE *)malloc(sz * 2); 76201941Smarcel status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 77201941Smarcel hin); 78201941Smarcel if (EFI_ERROR(status)) 79201941Smarcel free(hin); 80201941Smarcel } 81201941Smarcel if (EFI_ERROR(status)) 82201941Smarcel return (efi_status_to_errno(status)); 83201941Smarcel 84201941Smarcel /* Filter handles to only include FreeBSD partitions. */ 85201941Smarcel nin = sz / sizeof(EFI_HANDLE); 86201941Smarcel hout = hin + nin; 87201941Smarcel nout = 0; 88201941Smarcel 89201941Smarcel for (n = 0; n < nin; n++) { 90201941Smarcel status = BS->HandleProtocol(hin[n], &blkio_guid, &blkio); 91201941Smarcel if (EFI_ERROR(status)) 92201941Smarcel continue; 93201941Smarcel if (!blkio->Media->LogicalPartition) 94201941Smarcel continue; 95201941Smarcel hout[nout] = hin[n]; 96201941Smarcel nout++; 97201941Smarcel } 98201941Smarcel 99201941Smarcel err = efi_register_handles(&efipart_dev, hout, nout); 100201941Smarcel free(hin); 101201941Smarcel return (err); 102201941Smarcel} 103201941Smarcel 104201941Smarcelstatic void 105201941Smarcelefipart_print(int verbose) 106201941Smarcel{ 107201941Smarcel char line[80]; 108201941Smarcel EFI_BLOCK_IO *blkio; 109201941Smarcel EFI_HANDLE h; 110201941Smarcel EFI_STATUS status; 111201941Smarcel u_int unit; 112201941Smarcel 113201941Smarcel for (unit = 0, h = efi_find_handle(&efipart_dev, 0); 114201941Smarcel h != NULL; h = efi_find_handle(&efipart_dev, ++unit)) { 115201941Smarcel sprintf(line, " %s%d:", efipart_dev.dv_name, unit); 116201941Smarcel pager_output(line); 117201941Smarcel 118201941Smarcel status = BS->HandleProtocol(h, &blkio_guid, &blkio); 119201941Smarcel if (!EFI_ERROR(status)) { 120201941Smarcel sprintf(line, " %llu blocks", 121201941Smarcel (unsigned long long)(blkio->Media->LastBlock + 1)); 122201941Smarcel pager_output(line); 123201941Smarcel if (blkio->Media->RemovableMedia) 124201941Smarcel pager_output(" (removable)"); 125201941Smarcel } 126201941Smarcel pager_output("\n"); 127201941Smarcel } 128201941Smarcel} 129201941Smarcel 130201941Smarcelstatic int 131201941Smarcelefipart_open(struct open_file *f, ...) 132201941Smarcel{ 133201941Smarcel va_list args; 134201941Smarcel struct devdesc *dev; 135201941Smarcel EFI_BLOCK_IO *blkio; 136201941Smarcel EFI_HANDLE h; 137201941Smarcel EFI_STATUS status; 138201941Smarcel 139201941Smarcel va_start(args, f); 140201941Smarcel dev = va_arg(args, struct devdesc*); 141201941Smarcel va_end(args); 142201941Smarcel 143201941Smarcel h = efi_find_handle(&efipart_dev, dev->d_unit); 144201941Smarcel if (h == NULL) 145201941Smarcel return (EINVAL); 146201941Smarcel 147201941Smarcel status = BS->HandleProtocol(h, &blkio_guid, &blkio); 148201941Smarcel if (EFI_ERROR(status)) 149201941Smarcel return (efi_status_to_errno(status)); 150201941Smarcel 151201941Smarcel if (!blkio->Media->MediaPresent) 152201941Smarcel return (EAGAIN); 153201941Smarcel 154201941Smarcel dev->d_opendata = blkio; 155201941Smarcel return (0); 156201941Smarcel} 157201941Smarcel 158201941Smarcelstatic int 159201941Smarcelefipart_close(struct open_file *f) 160201941Smarcel{ 161201941Smarcel struct devdesc *dev; 162201941Smarcel 163201941Smarcel dev = (struct devdesc *)(f->f_devdata); 164201941Smarcel if (dev->d_opendata == NULL) 165201941Smarcel return (EINVAL); 166201941Smarcel 167201941Smarcel dev->d_opendata = NULL; 168201941Smarcel return (0); 169201941Smarcel} 170201941Smarcel 171201941Smarcel/* 172201941Smarcel * efipart_readwrite() 173201941Smarcel * Internal equivalent of efipart_strategy(), which operates on the 174201941Smarcel * media-native block size. This function expects all I/O requests 175201941Smarcel * to be within the media size and returns an error if such is not 176201941Smarcel * the case. 177201941Smarcel */ 178201941Smarcelstatic int 179201941Smarcelefipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, 180201941Smarcel char *buf) 181201941Smarcel{ 182201941Smarcel EFI_STATUS status; 183201941Smarcel 184201941Smarcel if (blkio == NULL) 185201941Smarcel return (ENXIO); 186201941Smarcel if (blk < 0 || blk > blkio->Media->LastBlock) 187201941Smarcel return (EIO); 188201941Smarcel if ((blk + nblks - 1) > blkio->Media->LastBlock) 189201941Smarcel return (EIO); 190201941Smarcel 191201941Smarcel switch (rw) { 192201941Smarcel case F_READ: 193201941Smarcel status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, 194201941Smarcel nblks * blkio->Media->BlockSize, buf); 195201941Smarcel break; 196201941Smarcel case F_WRITE: 197201941Smarcel if (blkio->Media->ReadOnly) 198201941Smarcel return (EROFS); 199201941Smarcel status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, 200201941Smarcel nblks * blkio->Media->BlockSize, buf); 201201941Smarcel break; 202201941Smarcel default: 203201941Smarcel return (ENOSYS); 204201941Smarcel } 205201941Smarcel 206201941Smarcel if (EFI_ERROR(status)) 207219683Smarcel printf("%s: rw=%d, status=%lu\n", __func__, rw, (u_long)status); 208201941Smarcel return (efi_status_to_errno(status)); 209201941Smarcel} 210201941Smarcel 211201941Smarcelstatic int 212201941Smarcelefipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, 213201941Smarcel size_t *rsize) 214201941Smarcel{ 215201941Smarcel struct devdesc *dev = (struct devdesc *)devdata; 216201941Smarcel EFI_BLOCK_IO *blkio; 217201941Smarcel off_t off; 218201941Smarcel char *blkbuf; 219201941Smarcel size_t blkoff, blksz; 220201941Smarcel int error; 221201941Smarcel 222201941Smarcel if (dev == NULL || blk < 0) 223201941Smarcel return (EINVAL); 224201941Smarcel 225201941Smarcel blkio = dev->d_opendata; 226201941Smarcel if (blkio == NULL) 227201941Smarcel return (ENXIO); 228201941Smarcel 229201941Smarcel if (size == 0 || (size % 512) != 0) 230201941Smarcel return (EIO); 231201941Smarcel 232201941Smarcel if (rsize != NULL) 233201941Smarcel *rsize = size; 234201941Smarcel 235201941Smarcel if (blkio->Media->BlockSize == 512) 236201941Smarcel return (efipart_readwrite(blkio, rw, blk, size / 512, buf)); 237201941Smarcel 238201941Smarcel /* 239201941Smarcel * The block size of the media is not 512B per sector. 240201941Smarcel */ 241201941Smarcel blkbuf = malloc(blkio->Media->BlockSize); 242201941Smarcel if (blkbuf == NULL) 243201941Smarcel return (ENOMEM); 244201941Smarcel 245201941Smarcel error = 0; 246201941Smarcel off = blk * 512; 247201941Smarcel blk = off / blkio->Media->BlockSize; 248201941Smarcel blkoff = off % blkio->Media->BlockSize; 249201941Smarcel blksz = blkio->Media->BlockSize - blkoff; 250201941Smarcel while (size > 0) { 251201941Smarcel error = efipart_readwrite(blkio, rw, blk, 1, blkbuf); 252201941Smarcel if (error) 253201941Smarcel break; 254201941Smarcel if (size < blksz) 255201941Smarcel blksz = size; 256201941Smarcel bcopy(blkbuf + blkoff, buf, blksz); 257201941Smarcel buf += blksz; 258201941Smarcel size -= blksz; 259201941Smarcel blk++; 260201941Smarcel blkoff = 0; 261201941Smarcel blksz = blkio->Media->BlockSize; 262201941Smarcel } 263201941Smarcel 264201941Smarcel free(blkbuf); 265201941Smarcel return (error); 266201941Smarcel} 267