1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 2011 Google, Inc. 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7ca987d46SWarner Losh * are met: 8ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13ca987d46SWarner Losh * 14ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca987d46SWarner Losh * SUCH DAMAGE. 25ca987d46SWarner Losh */ 26ca987d46SWarner Losh 27ca987d46SWarner Losh #include <sys/cdefs.h> 28ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 29ca987d46SWarner Losh 30ca987d46SWarner Losh /* 31ca987d46SWarner Losh * Userboot disk image handling. 32ca987d46SWarner Losh */ 33ca987d46SWarner Losh 34ca987d46SWarner Losh #include <sys/disk.h> 35ca987d46SWarner Losh #include <stand.h> 36ca987d46SWarner Losh #include <stdarg.h> 37ca987d46SWarner Losh #include <bootstrap.h> 38ca987d46SWarner Losh 39ca987d46SWarner Losh #include "disk.h" 40ca987d46SWarner Losh #include "libuserboot.h" 41ca987d46SWarner Losh 42ca987d46SWarner Losh struct userdisk_info { 43ca987d46SWarner Losh uint64_t mediasize; 44ca987d46SWarner Losh uint16_t sectorsize; 45ca987d46SWarner Losh int ud_open; /* reference counter */ 46ca987d46SWarner Losh void *ud_bcache; /* buffer cache data */ 47ca987d46SWarner Losh }; 48ca987d46SWarner Losh 49ca987d46SWarner Losh int userboot_disk_maxunit = 0; 50ca987d46SWarner Losh 51ca987d46SWarner Losh static int userdisk_maxunit = 0; 52ca987d46SWarner Losh static struct userdisk_info *ud_info; 53ca987d46SWarner Losh 54ca987d46SWarner Losh static int userdisk_init(void); 55ca987d46SWarner Losh static void userdisk_cleanup(void); 56ca987d46SWarner Losh static int userdisk_strategy(void *devdata, int flag, daddr_t dblk, 57ca987d46SWarner Losh size_t size, char *buf, size_t *rsize); 58ca987d46SWarner Losh static int userdisk_realstrategy(void *devdata, int flag, daddr_t dblk, 59ca987d46SWarner Losh size_t size, char *buf, size_t *rsize); 60ca987d46SWarner Losh static int userdisk_open(struct open_file *f, ...); 61ca987d46SWarner Losh static int userdisk_close(struct open_file *f); 62ca987d46SWarner Losh static int userdisk_ioctl(struct open_file *f, u_long cmd, void *data); 63ca987d46SWarner Losh static int userdisk_print(int verbose); 64ca987d46SWarner Losh 65ca987d46SWarner Losh struct devsw userboot_disk = { 66ca987d46SWarner Losh "disk", 67ca987d46SWarner Losh DEVT_DISK, 68ca987d46SWarner Losh userdisk_init, 69ca987d46SWarner Losh userdisk_strategy, 70ca987d46SWarner Losh userdisk_open, 71ca987d46SWarner Losh userdisk_close, 72ca987d46SWarner Losh userdisk_ioctl, 73ca987d46SWarner Losh userdisk_print, 74ca987d46SWarner Losh userdisk_cleanup 75ca987d46SWarner Losh }; 76ca987d46SWarner Losh 77ca987d46SWarner Losh /* 78ca987d46SWarner Losh * Initialize userdisk_info structure for each disk. 79ca987d46SWarner Losh */ 80ca987d46SWarner Losh static int 81ca987d46SWarner Losh userdisk_init(void) 82ca987d46SWarner Losh { 83ca987d46SWarner Losh off_t mediasize; 84ca987d46SWarner Losh u_int sectorsize; 85ca987d46SWarner Losh int i; 86ca987d46SWarner Losh 87ca987d46SWarner Losh userdisk_maxunit = userboot_disk_maxunit; 88ca987d46SWarner Losh if (userdisk_maxunit > 0) { 89ca987d46SWarner Losh ud_info = malloc(sizeof(*ud_info) * userdisk_maxunit); 90ca987d46SWarner Losh if (ud_info == NULL) 91ca987d46SWarner Losh return (ENOMEM); 92ca987d46SWarner Losh for (i = 0; i < userdisk_maxunit; i++) { 93ca987d46SWarner Losh if (CALLBACK(diskioctl, i, DIOCGSECTORSIZE, 94ca987d46SWarner Losh §orsize) != 0 || CALLBACK(diskioctl, i, 95ca987d46SWarner Losh DIOCGMEDIASIZE, &mediasize) != 0) 96ca987d46SWarner Losh return (ENXIO); 97ca987d46SWarner Losh ud_info[i].mediasize = mediasize; 98ca987d46SWarner Losh ud_info[i].sectorsize = sectorsize; 99ca987d46SWarner Losh ud_info[i].ud_open = 0; 100ca987d46SWarner Losh ud_info[i].ud_bcache = NULL; 101ca987d46SWarner Losh } 102ca987d46SWarner Losh } 103ca987d46SWarner Losh bcache_add_dev(userdisk_maxunit); 104ca987d46SWarner Losh return(0); 105ca987d46SWarner Losh } 106ca987d46SWarner Losh 107ca987d46SWarner Losh static void 108ca987d46SWarner Losh userdisk_cleanup(void) 109ca987d46SWarner Losh { 110ca987d46SWarner Losh 111ca987d46SWarner Losh if (userdisk_maxunit > 0) 112ca987d46SWarner Losh free(ud_info); 113ca987d46SWarner Losh } 114ca987d46SWarner Losh 115ca987d46SWarner Losh /* 116ca987d46SWarner Losh * Print information about disks 117ca987d46SWarner Losh */ 118ca987d46SWarner Losh static int 119ca987d46SWarner Losh userdisk_print(int verbose) 120ca987d46SWarner Losh { 121ca987d46SWarner Losh struct disk_devdesc dev; 122ca987d46SWarner Losh char line[80]; 123ca987d46SWarner Losh int i, ret = 0; 124ca987d46SWarner Losh 125ca987d46SWarner Losh if (userdisk_maxunit == 0) 126ca987d46SWarner Losh return (0); 127ca987d46SWarner Losh 128ca987d46SWarner Losh printf("%s devices:", userboot_disk.dv_name); 129ca987d46SWarner Losh if ((ret = pager_output("\n")) != 0) 130ca987d46SWarner Losh return (ret); 131ca987d46SWarner Losh 132ca987d46SWarner Losh for (i = 0; i < userdisk_maxunit; i++) { 133ca987d46SWarner Losh snprintf(line, sizeof(line), 134ca987d46SWarner Losh " disk%d: Guest drive image\n", i); 135ca987d46SWarner Losh ret = pager_output(line); 136ca987d46SWarner Losh if (ret != 0) 137ca987d46SWarner Losh break; 138de04d704SWarner Losh dev.dd.d_dev = &userboot_disk; 139de04d704SWarner Losh dev.dd.d_unit = i; 140ca987d46SWarner Losh dev.d_slice = -1; 141ca987d46SWarner Losh dev.d_partition = -1; 142ca987d46SWarner Losh if (disk_open(&dev, ud_info[i].mediasize, 143ca987d46SWarner Losh ud_info[i].sectorsize) == 0) { 144ca987d46SWarner Losh snprintf(line, sizeof(line), " disk%d", i); 145ca987d46SWarner Losh ret = disk_print(&dev, line, verbose); 146ca987d46SWarner Losh disk_close(&dev); 147ca987d46SWarner Losh if (ret != 0) 148ca987d46SWarner Losh break; 149ca987d46SWarner Losh } 150ca987d46SWarner Losh } 151ca987d46SWarner Losh return (ret); 152ca987d46SWarner Losh } 153ca987d46SWarner Losh 154ca987d46SWarner Losh /* 155ca987d46SWarner Losh * Attempt to open the disk described by (dev) for use by (f). 156ca987d46SWarner Losh */ 157ca987d46SWarner Losh static int 158ca987d46SWarner Losh userdisk_open(struct open_file *f, ...) 159ca987d46SWarner Losh { 160ca987d46SWarner Losh va_list ap; 161ca987d46SWarner Losh struct disk_devdesc *dev; 162ca987d46SWarner Losh 163ca987d46SWarner Losh va_start(ap, f); 164ca987d46SWarner Losh dev = va_arg(ap, struct disk_devdesc *); 165ca987d46SWarner Losh va_end(ap); 166ca987d46SWarner Losh 167de04d704SWarner Losh if (dev->dd.d_unit < 0 || dev->dd.d_unit >= userdisk_maxunit) 168ca987d46SWarner Losh return (EIO); 169de04d704SWarner Losh ud_info[dev->dd.d_unit].ud_open++; 170de04d704SWarner Losh if (ud_info[dev->dd.d_unit].ud_bcache == NULL) 171de04d704SWarner Losh ud_info[dev->dd.d_unit].ud_bcache = bcache_allocate(); 172de04d704SWarner Losh return (disk_open(dev, ud_info[dev->dd.d_unit].mediasize, 173de04d704SWarner Losh ud_info[dev->dd.d_unit].sectorsize)); 174ca987d46SWarner Losh } 175ca987d46SWarner Losh 176ca987d46SWarner Losh static int 177ca987d46SWarner Losh userdisk_close(struct open_file *f) 178ca987d46SWarner Losh { 179ca987d46SWarner Losh struct disk_devdesc *dev; 180ca987d46SWarner Losh 181ca987d46SWarner Losh dev = (struct disk_devdesc *)f->f_devdata; 182de04d704SWarner Losh ud_info[dev->dd.d_unit].ud_open--; 183de04d704SWarner Losh if (ud_info[dev->dd.d_unit].ud_open == 0) { 184de04d704SWarner Losh bcache_free(ud_info[dev->dd.d_unit].ud_bcache); 185de04d704SWarner Losh ud_info[dev->dd.d_unit].ud_bcache = NULL; 186ca987d46SWarner Losh } 187ca987d46SWarner Losh return (disk_close(dev)); 188ca987d46SWarner Losh } 189ca987d46SWarner Losh 190ca987d46SWarner Losh static int 191ca987d46SWarner Losh userdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size, 192ca987d46SWarner Losh char *buf, size_t *rsize) 193ca987d46SWarner Losh { 194ca987d46SWarner Losh struct bcache_devdata bcd; 195ca987d46SWarner Losh struct disk_devdesc *dev; 196ca987d46SWarner Losh 197ca987d46SWarner Losh dev = (struct disk_devdesc *)devdata; 198ca987d46SWarner Losh bcd.dv_strategy = userdisk_realstrategy; 199ca987d46SWarner Losh bcd.dv_devdata = devdata; 200de04d704SWarner Losh bcd.dv_cache = ud_info[dev->dd.d_unit].ud_bcache; 201ca987d46SWarner Losh return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, 202ca987d46SWarner Losh size, buf, rsize)); 203ca987d46SWarner Losh } 204ca987d46SWarner Losh 205ca987d46SWarner Losh static int 206ca987d46SWarner Losh userdisk_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, 207ca987d46SWarner Losh char *buf, size_t *rsize) 208ca987d46SWarner Losh { 209ca987d46SWarner Losh struct disk_devdesc *dev = devdata; 210ca987d46SWarner Losh uint64_t off; 211ca987d46SWarner Losh size_t resid; 212ca987d46SWarner Losh int rc; 213ca987d46SWarner Losh 214ca987d46SWarner Losh rw &= F_MASK; 215ca987d46SWarner Losh if (rw == F_WRITE) 216ca987d46SWarner Losh return (EROFS); 217ca987d46SWarner Losh if (rw != F_READ) 218ca987d46SWarner Losh return (EINVAL); 219ca987d46SWarner Losh if (rsize) 220ca987d46SWarner Losh *rsize = 0; 221de04d704SWarner Losh off = dblk * ud_info[dev->dd.d_unit].sectorsize; 222de04d704SWarner Losh rc = CALLBACK(diskread, dev->dd.d_unit, off, buf, size, &resid); 223ca987d46SWarner Losh if (rc) 224ca987d46SWarner Losh return (rc); 225ca987d46SWarner Losh if (rsize) 226ca987d46SWarner Losh *rsize = size - resid; 227ca987d46SWarner Losh return (0); 228ca987d46SWarner Losh } 229ca987d46SWarner Losh 230ca987d46SWarner Losh static int 231ca987d46SWarner Losh userdisk_ioctl(struct open_file *f, u_long cmd, void *data) 232ca987d46SWarner Losh { 233ca987d46SWarner Losh struct disk_devdesc *dev; 234ca987d46SWarner Losh int rc; 235ca987d46SWarner Losh 236ca987d46SWarner Losh dev = (struct disk_devdesc *)f->f_devdata; 237ca987d46SWarner Losh rc = disk_ioctl(dev, cmd, data); 238ca987d46SWarner Losh if (rc != ENOTTY) 239ca987d46SWarner Losh return (rc); 240ca987d46SWarner Losh 241de04d704SWarner Losh return (CALLBACK(diskioctl, dev->dd.d_unit, cmd, data)); 242ca987d46SWarner Losh } 243